以前用过一些Mock框架;使用jmockit时,我以为mock框架都差不多,jmockit也不例外。吃了一些苦头才发现,jmockit是多么的与众不同(中性词).
在我看来,jmockit作者的思维方式是扭曲的,jmockit的用法也是诡异的。要想充分利用jmockit的强大功能,你必须容忍它与众不同的地方。本文给出一些最近收集到的诡异点:
Mock行为中的诡异点
看起来只Mock了一个对象,实际上Mock了整个类
@Mocked //看起来只Mock了bean这个对象
private SimpleBean bean;
@Test
public void test_MockedInstance() throws Exception {
bean.throwException(); // 不会报异常,因为bean已经被mock了. 这个好理解.
}
@Test
public void test_AnotherInstance() throws Exception {
SimpleBean bean2 = new SimpleBean();
bean2.throwException(); // 也不会报异常,因为SimpleBean的任何一个实例都被Mock了。想不到吧?
}
看起来只Mock了本类,实际上这个类的父类及所有祖先类都被Mock了
@Mocked
private SubSimpleBean bean; //看起来只Mock了SubSimpleBean类
@Test
public void test_AnotherInstance() throws Exception {
SimpleBean bean2 = new SimpleBean(); //SubSimpleBean的父类
bean2.throwException(); // 不会报异常,因为SubSimpleBean的父类也被Mock了 (所有祖先类都被Mock, 但java.lang.Object除外)
}
要Mock一个类,可以把这个类的实例作为测试方法的形式参数,也算是有创意了
@Test
public void putTest(final Cache mockedCache) { //被mock对象作为方法的参数
new Expectations() {
{
mockedCache.put(bean);
}
};
....
}
Expectation中的诡异点
Expectation中不但做了mocking,也隐式地做了verifying
new Expectations() {
{
/**
* 下面的代码做了两件事:
* 1. mock dao的行为: dao.getNumOfBeans()如果被调用,则返回值是100<br/>
* 2. 同时,期望dao.getNumOfBeans()在测试时被调用,如果没调用,意味测试未通过
*/
dao.getNumOfBeans();
result = 100;
}
};
Expectioan里的隐式verification只跟被Mock的方法有关
@Test
public void test_Not_Mocked_Object(){
Service service = new Service();
...
new Expectations(){{
nonMockedClass.someMethod(); //不会出错。虽然service.saveAndCache(bean)时不会调用NonMockedClass的方法,但由于NonMockedClass不是被mock类,jmockit不会验证跟它有关的语句
}};
service.saveAndCache(bean);
}
Expectations录制了方法未执行,会报错;未录制但执行了,却不会报错
@Test
public void test_Not_Invoked_Method(){
Service service = new Service();
service.setCache(cache);
service.setDao(dao);
final SimpleBean bean = new SimpleBean();
new Expectations(){{
mockedList.someMethod(); //会出错,因为service.saveAndCache(bean)时不需要调任何MockedList的方法
}};
service.saveAndCache(bean);
}
@Test
public void test_NoCoverage(){
Service service = new Service();
service.setCache(cache);
service.setDao(dao);
new Expectations(){{
//测试可以通过,虽然这里没有录制任何被mock类的方法
}};
service.saveAndCache(new SimpleBean());
}
@Test
public void test_CoverOnlyOne(){
Service service = new Service();
service.setCache(cache);
service.setDao(dao);
final SimpleBean bean = new SimpleBean();
new Expectations(){{
//测试可以通过,虽然这里只录制了部分被mock类的方法
dao.save(bean);
}};
service.saveAndCache(bean);
}