Mockito是一个模拟框架(请参阅两种不同的模拟方法 ),它是EasyMock的分支。 无论使用哪种模拟框架,一个共同的功能就是能够通过JDK Proxy类模拟接口。 这很好,但是必须显式地模拟在测试过程中要使用的每种方法。
如果我想模拟一个已有的实现,并使用某些方法提供适合我的行为该怎么办? 今天,我遇到了这个案例:我有一个想要重用的旧式帮助程序类。 此类使用commons-http-client简化了调用URL的过程。 它具有属性访问器,就像任何旧的POJO一样,即使在测试范围内,我也确实需要,并且使用先前设置的属性(例如URL)进行真正调用的方法。 但是,它没有实现任何接口。 看起来是这样的:
publicclassLegacyHelper{
// Various attributes
...
// Various accessors to get/set these properties
...
// One big method that uses external resources (very bad for Unit Testing)
publicintcallUrl(){
...
}
}
尽管Mockito缺乏详尽的文档(许多Google Code项目共有的一个特征,令我沮丧的是),但我碰巧遇到了Mockito.spy()
方法。 这种魔术方法可以在真实对象上创建代理(因此称为间谍)。 除非将这些方法存根,否则它将其方法调用委托给代理对象。 这意味着我可以依靠吸气剂/设置剂来完成他们的工作,同时消除破坏隔离测试的传统方法。
publicclassMyTest{
// This I don't want to test but my class uses it
privateLegacyHelperhelper;
@BeforeMethod
publicvoidsetUp(){
helper=Mockito.spy(newLegacyHelper());
Mockito.when(helper.callUrl()).thenReturn(0);
}
@Test
publicvoidtestCall(){
// Now I can use helper without it really calling anything
helper.callUrl();
// Do real testing here
...
}
}
这只是第一步。 如果需要在整个应用程序中提供间谍对象怎么办? Spring当然可以通过FactoryBean
接口来提供帮助。 当Spring创建一个新实例时,如果引用的类是FactoryBean
类型,它将调用new
运算符或getObject()方法。 我们的间谍工厂如下所示:
publicclassSpyFactoryBean{
// Real or spied object
privateObjectreal;
publicvoidsetReal(Objectobject){
real=object;
}
publicbooleanisSingleton(){
returnfalse;
}
publicClassgetObjectType(){
returnreal.getClass();
}
publicObjectgetObject(){
returnMock.spy(real);
}
}
要在Spring上下文文件中使用它:
<?xml version="1.0" encoding="ISO-8859-1"?>
<beans>
<beanid="legacyHelper"class="LegacyHelper"/>
<beanid="mockHelper"class="SpyFactoryBean"dependency-check="objects">
<propertyname="real"ref="legacyHelper"/>
</bean>
</beans>
现在,您已经拥有了一个间谍工厂,您可以在项目的测试中重复使用这些间谍,甚至更好地将其运用于企业的所有项目中。 唯一要做的就是不要忘记对可能有副作用的方法加桩。