mockito中兩種部分mock的實現,spy、callRealMethod

 

什麼是類的部分mock(partial mock)?
A:部分mock是說一個類的方法有些是實際調用,有些是使用mockito的stubbing(樁實現)。java

 

爲何須要部分mock?app

A:當須要測試一個組合方法(一個方法須要其它多個方法協做)的時候,某個葉子方法(只供別人調用,本身不依賴其它反覆)已經被測試過,咱們其實不須要再次測試這個葉子方法,so,讓葉子打樁實現返回結果,上層方法實際調用並測試。less

mockito實現部分mock的兩種方式:spy和callRealMethod()eclipse

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;
    }

}

 

輸出爲:this

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()方法被真正執行,因此就須要另外一種寫法。spa

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

 

 

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();

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

相關文章
相關標籤/搜索