jmockit中的诡异陷阱

以前用过一些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);
 }

Leave a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.