Cherry
Cherry

Reputation: 33618

How mock spring component during tests without extracting interface from it?

There is a spring componet with @Component annotation, it is just java class (not interface) with annotated @Autowired fields. I am trying to create mock like that:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
    >
  <bean id="myComponent" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="com.MyComponent"/>
  </bean>
</beans>

And got an exception that some of fields are not autowired. This happens, because when Spring see <constructor-arg value="com.MyComponent"/> it try to instantiate MyComponent bean and pass it to factory method.

I have tried to extract interface from component, in that case mocking works, but is there a way to make it working without extracting interface?

Also

I have tried adding type="java.lang.Class" but got same errors.

  <bean id="myComponent" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg  type="java.lang.Class"  value="com.MyComponent"/>
  </bean>

Any ideas?

Upvotes: 1

Views: 1510

Answers (1)

Tom Verelst
Tom Verelst

Reputation: 16002

Spring cannot autowire the bean because the type of the created bean is java.lang.Object and not com.myComponent. Apparently the order of the definitions in the XML matters as well.

Jayway has a very nice blog post about this: Spring Integration Tests - Creating Mock Objects

You can create a FactoryBean which returns the correct class:

public class MockitoFactoryBean<T> implements FactoryBean<T> {

    private Class<T> classToBeMocked;

    /**
     * Creates a Mockito mock instance of the provided class.
     * @param classToBeMocked The class to be mocked.
     */
    public MockitoFactoryBean(Class<T> classToBeMocked) {
        this.classToBeMocked = classToBeMocked;
    }

    @Override
    public T getObject() throws Exception {
        return Mockito.mock(classToBeMocked);
    }

    @Override
    public Class<?> getObjectType() {
        return classToBeMocked;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

Using this factory bean, you can create a config like this:

<bean id="myComponent" class="com.yourpackage.MockitoFactoryBean">
    <constructor-arg name="classToBeMocked" value="com.myComponent" />
</bean>

This will mock your component and the object type will com.myComponent.


Update

This is the original answer and explanation (using EasyMock): Autowiring of beans generated by EasyMock factory-method?

Upvotes: 2

Related Questions