mockito中两种部分mock的实现,spy、callRealMethod

简介: 什么是类的部分mock(partial mock)?A:部分mock是说一个类的方法有些是实际调用,有些是使用mockito的stubbing(桩实现)。   为什么需要部分mock? A:当需要测试一个组合方法(一个方法需要其它多个方法协作)的时候,某个叶子方法(只供别人调用,自己不依赖其它反复)已经被测试过,我们其实不需要再次测试这个叶子方法,so,让叶子打桩实现返回结果,上层方法实际调用并测试。

 

什么是类的部分mock(partial mock)?
A:部分mock是说一个类的方法有些是实际调用,有些是使用mockito的stubbing(桩实现)。

 

为什么需要部分mock?

A:当需要测试一个组合方法(一个方法需要其它多个方法协作)的时候,某个叶子方法(只供别人调用,自己不依赖其它反复)已经被测试过,我们其实不需要再次测试这个叶子方法,so,让叶子打桩实现返回结果,上层方法实际调用并测试。

mockito实现部分mock的两种方式:spy和callRealMethod()

spy实现:

package spy;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.util.LinkedList;
import java.util.List;

import org.junit.Test;

public class SpyDemo {

    @Test
    public void spy_Simple_demo(){
        List<String> list = new LinkedList<String>();  
        List<String> spy = spy(list);  
        when(spy.size()).thenReturn(100);  
        
        spy.add("one");  
        spy.add("two");  
        
/*        spy的原理是,如果不打桩默认都会执行真实的方法,如果打桩则返回桩实现。
        可以看出spy.size()通过桩实现返回了值100,而spy.get(0)则返回了实际值*/
        assertEquals(spy.get(0), "one");  
        assertEquals(100, spy.size());  
    }
    
    @Test  
    public void spy_Procession_Demo() {  
        Jack spyJack = spy(new Jack());  
        //使用spy的桩实现实际还是会调用stub的方法,只是返回了stub的值
        when(spyJack.go()).thenReturn(false);  
        assertFalse(spyJack.go()); 
        
        //不会调用stub的方法
        doReturn(false).when(spyJack).go();
        assertFalse(spyJack.go()); 
    } 
    
}



class Jack {  
    public boolean go() {  
        System.out.println("I say go go go!!");  
        return true;  
    }  
}

 

Spy类就可以满足我们的要求。如果一个方法定制了返回值或者异常,那么就会按照定制的方式被调用执行;如果一个方法没被定制,那么调用的就是真实类的方法。

如果我们定制了一个方法A后,再下一个测试方法中又想调用真实方法,那么只需在方法A被调用前,调用Mockito.reset(spyObject);就行了。

package spy;

import static org.mockito.Mockito.when;

import org.mockito.Mockito;

public class TestMockObject {

    public static void main(String[] args) {

        TestMockObject mock = Mockito.mock(TestMockObject.class);
        System.out.println(mock.test1());
        System.out.println(mock.test2());

        TestMockObject spy = Mockito.spy(new TestMockObject());
        System.out.println(spy.test1());
        System.out.println(spy.test2());

        when(spy.test1()).thenReturn(100);
        System.out.println(spy.test1());

        Mockito.reset(spy);
        System.out.println(spy.test1());
        System.out.println(spy.test2());

        when(spy.test1()).thenReturn(104);
        System.out.println(spy.test1());
    }

    public int test1() {
        System.out.print("RealTest1()!!! - ");
        return 1;
    }

    public int test2() {
        System.out.print("RealTest2()!!! - ");
        return 2;
    }

}

 

输出为:

0
0
RealTest1()!!! - 1
RealTest2()!!! - 2
RealTest1()!!! - 100
RealTest1()!!! - 1
RealTest2()!!! - 2
RealTest1()!!! - 104

要注意的是,对Spy对象的方法定制有时需要用另一种方法:
===============================================================================
Importantgotcha on spying real objects!

Sometimes it's impossible to usewhen(Object) for stubbing spies. Example:
List list = new LinkedList();
List spy = spy(list);

//Impossible: real method is called so spy.get(0) throwsIndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");

//You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);
===============================================================================
因为用when(spy.f1())会导致f1()方法被真正执行,所以就需要另一种写法。

http://blog.csdn.net/dc_726/article/details/8568537

 

 

callRealMethod()实现

Use doCallRealMethod() when you want to call the real implementation of a method.

As usual you are going to read the partial mock warning: Object oriented programming is more less tackling complexity by dividing the complexity into separate, specific, SRPy objects. How does partial mock fit into this paradigm? Well, it just doesn't... Partial mock usually means that the complexity has been moved to a different method on the same object. In most cases, this is not the way you want to design your application.

However, there are rare cases when partial mocks come handy: dealing with code you cannot change easily (3rd party interfaces, interim refactoring of legacy code etc.) However, I wouldn't use partial mocks for new, test-driven & well-designed code.

See also javadoc Mockito.spy(Object) to find out more about partial mocks. Mockito.spy() is a recommended way of creating partial mocks. The reason is it guarantees real methods are called against correctly constructed object because you're responsible for constructing the object passed to spy() method.

Example:


   Foo mock = mock(Foo.class);
   doCallRealMethod().when(mock).someVoidMethod();

   // this will call the real implementation of Foo.someVoidMethod()
   mock.someVoidMethod();
 
AI 代码解读

See examples in javadoc for Mockito class

Returns:
stubber - to select a method for stubbing

 

package callRealMethod;

import org.junit.Test;
import static org.mockito.Mockito.*;

public class CallMethodDemo {
    @Test  
    public void callRealMethodTest() {  
        Jerry jerry = mock(Jerry.class);  
      
        doCallRealMethod().when(jerry).goHome();  
        doCallRealMethod().when(jerry).doSomeThingB();  
      
        jerry.goHome();  
      
        verify(jerry).doSomeThingA();  
        verify(jerry).doSomeThingB();  
    }  
}

class Jerry {  
    public void goHome() {  
        doSomeThingA();  
        doSomeThingB();  
    }  
  
    // real invoke it.  
    public void doSomeThingB() {  
        System.out.println("good day");  
  
    }  
  
    // auto mock method by mockito  
    public void doSomeThingA() {  
        System.out.println("you should not see this message.");  
  
    }  
}

  通过代码可以看出Jerry是一个mock对象, goHome()和doSomeThingB()是使用了实际调用技术,而doSomeThingA()被mockito执行了默认的answer行为(这里是个void方法,so,什么也不干)。

 

总结:

    spy和callrealmethod都可以实现部分mock,唯一不同的是通过spy做的桩实现仍然会调用实际方法(我都怀疑这是不是作者的bug)。

    批注:spy方法需要使用doReturn方法才不会调用实际方法。

 

    mock技术是实施TDD过程必备的装备,熟练掌握mockito(或者其他工具)可以更有效的进行测试。虽然mockito作者也觉得部分测试不是好的设计,但是在java这样一个不是完全面向对象技术的平台上,我们其实没必要过分纠结这些细节,简洁,可靠的代码才是我们需要的。

http://heipark.iteye.com/blog/1496603

 

相关文章
Mockito 应用指南
Mockito 是一个针对 Java 的 mock 框架。
120 0
单元测试问题之Mockito 3.4mock静态方法如何解决
单元测试问题之Mockito 3.4mock静态方法如何解决
401 1
单元测试问题之在Mockito中静态方法的调用,如何模拟
单元测试问题之在Mockito中静态方法的调用,如何模拟
mockito的详细使用
1.概述 mock,一种JAVA单元测试技术,mock允许使用模拟对象替换测试中的系统部件,并断言它们是如何被使用的一项技术。 当某个接口或者功能模块依赖于其他接口或者模块,而所依赖的模块或接口未开发完毕,可以使用mock模拟依赖的模块。 mockito,JAVA单元测试中使用频率最高的mock框架之一。 mock遵循流程:输入—期望—验证
277 0
Mockito框架里面的@Mock注解原理
一文看懂@Mock注解的底层的底层原理:@Mock注解的底层其实就是用cglib
4106 0
PowerMock(一):PowerMock的基本使用
您好,我是码农飞哥,感谢您阅读本文!本文主要介绍PowerMock的基本使用。
1556 0
spring单元测试之Mockito
Mockito 是一个针对 Java 的单元测试模拟框架,它与 EasyMock 和 jMock 很相似,都是为了简化单元测试过程中测试上下文 ( 或者称之为测试驱动函数以及桩函数 ) 的搭建而开发的工具
442 0
mock打桩之EasyMock
TDD是测试驱动开发(Test-Driven Development)的英文简称,是敏捷开发中的一项核心实践和技术,也是一种设计方法论。TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。TDD虽是敏捷方法的核心实践,但不只使用于XP(Extreme Programming),同样可以适用于其他开发方法和过程。
mock打桩之EasyMock
Junit单元测试类、反射、注解
Junit单元测试类、反射、注解
197 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等