Spring Test模拟一个依赖项

时间:2013-09-09 10:39:17

标签: java spring unit-testing dependency-injection spring-test

假设我将XML Spring配置的这两部分放在两个不同的文件中;

//daoContext.xml
<bean id="myDao" class="com.MyDao"/>

//logicContext.xml
<bean id="myLogic" class="com.MyLogic">
    <constructor-arg ref="myDao"/><!--or other type of injection--?
</bean>

还有测试类:

@ContextConfiguration("logicContext.xml")
public class BaseLogicTest extends AbstractTestNGSpringContextTests {
    @Autowired
    private MyLogic myLogic;

    @Test
    public void testMyTestable() {
        //...
    }
}

现在,我想要的是能够模拟MyDao类并注入MyLogicBaseLogicTest注入MyLogic所以我可以使用MyDao嘲笑{{1}}。这是否可以使用弹簧/弹簧测试?

2 个答案:

答案 0 :(得分:2)

最简单的解决方案是加载所有xml。并在测试用例中手动替换依赖。

@ContextConfiguration("logicContext.xml")
public class BaseLogicTest extends AbstractTestNGSpringContextTests {
    @Autowired
    private MyLogic myLogic;

    @Before
    public void injectTestDoubles() {
        myLogic.setMyDao(...);
    }

    @DirtiesContext
    @Test ...//test methods
}

但是这会破坏应用程序上下文,所以如果在其他测试用例中需要“真正的”myDao共享相同的应用程序上下文,则需要@DirtiesContext。

最受欢迎的解决方案(我的个人意见:P)是使用mockito和特定于测试的xml。

//daoContext.xml
<bean id="myDao" class="com.MyDao"/>

//logicContext.xml
<bean id="myLogic" class="com.MyLogic">
    <constructor-arg ref="myDao"/><!--or other type of injection--?
</bean>

//test-logicContext.xml
<bean id="myDao" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="com.MyDao" />
</bean>

@ContextConfiguration({"logicContext.xml", "test-logicContext.xml"})
public class BaseLogicTest extends AbstractTestNGSpringContextTests {
    @Autowired
    private MyLogic myLogic;

    @Autowired
    private MyDao myDao;//retrieve mock so you could define expectations

    @Test //test methods

    @After public void clearMocks() {
        Mockito.reset(myDao);//this is important if you have several test methods
    }
}

此解决方案适用于其他模拟框架,如easyMock。

答案 1 :(得分:1)

您可以通过创建FactoryBean来创建MyDao(或任何)模拟注入您的MyLogic实例。

public class FactoryBeanForMocks<T> implements FactoryBean<T> {
    private Class<T> mockClass;

    public FactoryBeanForMocks(Class<T> mockClass) {
        super();
        this.mockClass = mockClass;
    }

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

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

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

}

将工厂bean条目放入logicContext.xml,以便可以将MyDao的模拟注入MyLogic

//logicContext.xml
<bean id="myLogic" class="com.MyLogic">
    <constructor-arg ref="myDao"/><!--or other type of injection--?
</bean>
<bean id="myDao" class="x.y.z.FactoryBeanForMocks">
        <constructor-arg name="mockClass" value="x.y.MyDao"></constructor-arg>
</bean>

这是你的测试类:

@ContextConfiguration("logicContext.xml")
public class BaseLogicTest extends AbstractTestNGSpringContextTests {
    @Autowired
    private MyLogic myLogic;

    //You can inject the mock myDao into it so that you can stub/verify method calls on it
    @Autowired
    private MyDao myDao;

    @Test
    public void testMyTestable() {
        //...
    when(myDao.process()).thenReturn("a");//stubbing myDao.process()
    assertEquals("a", myLogic.processRequest());// assuming myLogic.processRequest() calls myDao.process()
    }
}