Autowiring beans, созданный программой EasyMock factory -method?
У меня есть проблема, которая кажется мне действительно странной. У меня есть следующая настройка:
Интерфейс:
package com.example;
public interface SomeDependency {
}
Компонент
A spring:
package com.example;
@Component
public class SomeClass {
}
A spring тестовая конфигурация с посмеянной bean, сгенерированной 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>
И unit test:
@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)}
Итак, мои вопросы:
- Почему spring не удается отключить зависимость от SomeClass (когда ему удастся автоподключить ту же зависимость к SomeClassTest)?
- Как я могу изменить SomeClassTest или testconfig.xml, чтобы пройти тесты?
Комментарий: В действительности класс, представленный SomeClass, является частью структуры. Следовательно, он не может быть легко обновлен, по крайней мере, не в разумные сроки.
Зависимости:
- Spring: 3.0.5.RELEASE
- EasyMock: 3.0
Edit:
Как и в случае с spring 3.2 RC1, проблема с общими методами factory и макетными объектами была решена.
/Маттиас
Ответы
Ответ 1
Кажется, что порядок определений в xml действительно имеет значение при использовании фабрик для создания beans с помощью autowiring. Если вы поместите объявление someInterfaceMock
выше component-scan
, оно будет работать.
Некоторые пояснения почему: Когда Spring пытается autowire SomeClass
, он ищет bean типа SomeDependency
. На этом этапе someInterfaceMock
по-прежнему остается factory, поэтому Spring проверяет подпись метода factory EasyMock.createMock(...)
, который возвращает <T>
, поэтому Spring находит только Object
, который не является типом, требуемым.
Лучше всего использовать интерфейс Spring FactoryBean
для создания ваших mocks.
Вот базовая реализация, которая должна работать:
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 (порядок не имеет значения!):
<bean class="com.example.EasyMockFactoryBean">
<property name="mockedClass" value="com.example.Dependancy"/>
</bean>