Автопроводка бобов, генерируемых фабричным методом EasyMock? - PullRequest
14 голосов
/ 14 июня 2011

У меня есть проблема, которая кажется мне действительно странной. У меня есть следующие настройки:

Интерфейс:

package com.example;

public interface SomeDependency {
}

Компонент пружины:

package com.example;

@Component
public class SomeClass {
}

Конфигурация весеннего теста с фиктивным бином, сгенерированным EasyMock:

<beans ....>
    <context:component-scan base-package="com.example"/>

    <bean id="someInterfaceMock" class="org.easymock.EasyMock" factory-method="createMock">
        <constructor-arg value="com.example.SomeDependency" />
    </bean> 
</beans>

И юнит-тест:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/testconfig.xml")
public class SomeClassTest {

    @Autowired
    SomeClass someClass;

    @Autowired
    SomeDependency someDependency;

    @Test
    public void testSomeClass() throws Exception {
        assertNotNull(someClass);
    }

    @Test
    public void testSomeDependency() throws Exception {
        assertNotNull(someDependency);
    }
}

Проект компилируется и тесты проходят без каких-либо проблем, т. Е. Автоматическое подключение как SomeClass ("реальный" объект), так и SomeDependency (фиктивный объект, сгенерированный EasyMock), завершается успешно.

Однако, если я изменю реализацию SomeClass на:

@Component
public class SomeClass {

    @Autowired
    SomeDependency someDependency;
}

оба теста не пройдены, потому что

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.example.SomeDependency] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Итак, мои вопросы:

  1. Почему Spring не может автоматически связать зависимость с SomeClass (когда ему удается автоматически связать ту же зависимость с SomeClassTest )?
  2. Как я могу изменить SomeClassTest или testconfig.xml для прохождения тестов?

Комментарий: в действительности класс, представленный SomeClass , является частью фреймворка. Следовательно, он не может быть легко обновлен, по крайней мере, в разумные сроки.

Зависимость:

  • Весна: 3.0.5. РЕЛИЗ
  • EasyMock: 3,0

Edit:

Начиная с Spring 3.2 RC1, проблема с общими фабричными методами и фиктивными объектами была решена .

/ Маттиас

1 Ответ

21 голосов
/ 14 июня 2011

Кажется, порядок определений в xml действительно имеет значение при использовании фабрик для создания bean-компонентов с автопроводкой.Если вы поместите объявление someInterfaceMock выше component-scan, оно будет работать.

Некоторые пояснения, почему: когда Spring пытается выполнить автоматическую передачу SomeClass, он ищет компонент типа SomeDependency.На этом этапе someInterfaceMock все еще является фабрикой, поэтому Spring проверяет подпись фабричного метода EasyMock.createMock(...), который возвращает <T>, поэтому Spring находит только Object, который не является требуемым типом.

Aлучшим способом было бы использовать FactoryBean интерфейс Spring для создания своих макетов.

Вот базовая реализация, которая должна работать:

public class EasyMockFactoryBean<T> implements FactoryBean<T> {
    private Class<T> mockedClass;

    public void setMockedClass(Class mockedClass) {
        this.mockedClass = mockedClass;
    } 

    public T getObject() throws Exception {
        return EasyMock.createMock(mockedClass);
    }

    public Class<T> getObjectType() {
        return mockedClass;
    }

    public boolean isSingleton() {
        return true;
    } 

}

Вот определение бина (порядок выигранных 'не имеет значения!):

<bean class="com.example.EasyMockFactoryBean">
    <property name="mockedClass" value="com.example.Dependancy"/>
</bean>    
...