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>