• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • TDD(測試驅動開發)中Mockito使用淺談

    發表于:2016-07-21來源:jianshu作者:流水不腐小夏點擊數: 標簽:tdd
    在軟件開發的世界之外, "mock"一詞是指模仿或者效仿。 因此可以將“mock”理解為一個替身,替代者. 在軟件開發中提及"mock",通常理解為模擬對象或者Fake。

    Mockito簡介

    • 什么是mock?
      在軟件開發的世界之外, "mock"一詞是指模仿或者效仿。 因此可以將“mock”理解為一個替身,替代者. 在軟件開發中提及"mock",通常理解為模擬對象或者Fake。

    • 為什么需要Mock?
      Mock是為了解決units之間由于耦合而難于被測試的問題。所以mock object是unit test的一部分。

    Mock的好處是什么?

    • 提前創建測試,TDD(測試驅動開發)

      這是個最大的好處吧。如果你創建了一個Mock那么你就可以在service接口創建之前寫Service Tests了,這樣你就能在開發過程中把測試添加到你的自動化測試環境中了。換句話說,模擬使你能夠使用測試驅動開發。

    • 團隊可以并行工作

      這類似于上面的那點;為不存在的代碼創建測試。但前面講的是開發人員編寫測試程序,這里說的是測試團隊來創建。當還沒有任何東西要測的時候測試團隊如何來創建測試呢?模擬并針對模擬測試!這意味著當service借口需要測試時,實際上QA團隊已經有了一套完整的測試組件;沒有出現一個團隊等待另一個團隊完成的情況。這使得模擬的效益型尤為突出了。

    • 你可以創建一個驗證或者演示程序。

      由于Mocks非常高效,Mocks可以用來創建一個概念證明,作為一個示意圖,或者作為一個你正考慮構建項目的演示程序。這為你決定項目接下來是否要進行提供了有力的基礎,但最重要的還是提供了實際的設計決策。

    • 為無法訪問的資源編寫測試

      這個好處不屬于實際效益的一種,而是作為一個必要時的“救生圈”。有沒有遇到這樣的情況?當你想要測試一個service接口,但service需要經過防火墻訪問,防火墻不能為你打開或者你需要認證才能訪問。遇到這樣情況時,你可以在你能訪問的地方使用MockService替代,這就是一個“救生圈”功能。

    • Mock 可以交給用戶

      在有些情況下,某種原因你需要允許一些外部來源訪問你的測試系統,像合作伙伴或者客戶。這些原因導致別人也可以訪問你的敏感信息,而你或許只是想允許訪問部分測試環境。在這種情況下,如何向合作伙伴或者客戶提供一個測試系統來開發或者做測試呢?最簡單的就是提供一個mock,無論是來自于你的網絡或者客戶的網絡。soapUI mock非常容易配置,他可以運行在soapUI或者作為一個war包發布到你的java服務器里面。

    • 隔離系統

      有時,你希望在沒有系統其他部分的影響下測試系統單獨的一部分。由于其他系統部分會給測試數據造成干擾,影響根據數據收集得到的測試結論。使用mock你可以移除掉除了需要測試部分的系統依賴的模擬。當隔離這些mocks后,mocks就變得非常簡單可靠,快速可預見。這為你提供了一個移除了隨機行為,有重復模式并且可以監控特殊系統的測試環境。

    Mockito使用示例

    模擬對象

    // 模擬LinkedList 的一個對象  
    LinkedList mockedList = mock(LinkedList.class);
    // 此時調用get方法,會返回null,因為還沒有對方法調用的返回值做模擬
    System.out.println(mockedList.get(0));

    模擬方法調用的返回值

    // 模擬獲取第一個元素時,返回字符串first。  給特定的方法調用返回固定值在官方說法中稱為stub。
    when(mockedList.get(0)).thenReturn("first");
    // 此時打印輸出first
    System.out.println(mockedList.get(0));

    模擬方法調用拋出異常

    // 模擬獲取第二個元素時,拋出RuntimeException  
    when(mockedList.get(1)).thenThrow(new RuntimeException());
    // 此時將會拋出RuntimeException  
    System.out.println(mockedList.get(1));

    如果一個函數沒有返回值類型,那么可以使用此方法模擬異常拋出

    doThrow(new RuntimeException("clear exception")).when(mockedList).clear();
    mockedList.clear();

    模擬調用方法時的參數匹配

    // anyInt()匹配任何int參數,這意味著參數為任意值,其返回值均是element  
    when(mockedList.get(anyInt())).thenReturn("element");
    // 此時打印是element
    System.out.println(mockedList.get(999));

    模擬方法調用次數

    // 調用add一次
    mockedList.add("once"); 
    // 下面兩個寫法驗證效果一樣,均驗證add方法是否被調用了一次
    verify(mockedList).add("once");
    verify(mockedList, times(1)).add("once");

    校驗行為

     // mock creation
     List mockedList = mock(List.class);
     // using mock object
     mockedList.add("one");
     mockedList.clear();
     //verification
     verify(mockedList).add("one");
     verify(mockedList).clear();

    模擬方法調用(Stubbing)

     //You can mock concrete classes, not just interfaces
     LinkedList mockedList = mock(LinkedList.class);
     //stubbing
     when(mockedList.get(0)).thenReturn("first");
     when(mockedList.get(1)).thenThrow(new RuntimeException());
     //following prints "first"
     System.out.println(mockedList.get(0));
     //following throws runtime exception
     System.out.println(mockedList.get(1));
     //following prints "null" because get(999) was not stubbed
     System.out.println(mockedList.get(999));
    
     verify(mockedList).get(0);

    參數匹配

     //stubbing using built-in anyInt() argument matcher
     when(mockedList.get(anyInt())).thenReturn("element");
     //stubbing using custom matcher (let's say isValid() returns your own matcher implementation):
     when(mockedList.contains(argThat(isValid()))).thenReturn("element");
     //following prints "element"
     System.out.println(mockedList.get(999));
     //you can also verify using an argument matcher
     verify(mockedList).get(anyInt());
     //argument matchers can also be written as Java 8 Lambdas
     verify(mockedList).add(someString -> someString.length() > 5);

    校驗方法調用次數

     //using mock
     mockedList.add("once");
    
     mockedList.add("twice");
     mockedList.add("twice");
    
     mockedList.add("three times");
     mockedList.add("three times");
     mockedList.add("three times");
     //following two verifications work exactly the same - times(1) is used by default
     verify(mockedList).add("once");
     verify(mockedList, times(1)).add("once");
     //exact number of invocations verification
     verify(mockedList, times(2)).add("twice");
     verify(mockedList, times(3)).add("three times");
     //verification using never(). never() is an alias to times(0)
     verify(mockedList, never()).add("never happened");
     //verification using atLeast()/atMost()
     verify(mockedList, atLeastOnce()).add("three times");
     verify(mockedList, atLeast(2)).add("five times");
     verify(mockedList, atMost(5)).add("three times");

    模擬無返回方法拋出異常

    doThrow(new RuntimeException()).when(mockedList).clear();
    //following throws RuntimeException:
    mockedList.clear();

    校驗方法調用順序

     // A. Single mock whose methods must be invoked in a particular order
     List singleMock = mock(List.class);
     //using a single mock
     singleMock.add("was added first");
     singleMock.add("was added second");
     //create an inOrder verifier for a single mock
     InOrder inOrder = inOrder(singleMock);
     //following will make sure that add is first called with "was added first, then with "was added second"
     inOrder.verify(singleMock).add("was added first");
     inOrder.verify(singleMock).add("was added second");
    
     // B. Multiple mocks that must be used in a particular order
     List firstMock = mock(List.class);
     List secondMock = mock(List.class);
     //using mocks
     firstMock.add("was called first");
     secondMock.add("was called second");
     //create inOrder object passing any mocks that need to be verified in order
     InOrder inOrder = inOrder(firstMock, secondMock);
     //following will make sure that firstMock was called before secondMock
     inOrder.verify(firstMock).add("was called first");
     inOrder.verify(secondMock).add("was called second");
     // Oh, and A + B can be mixed together at will

    校驗方法是否從未調用

     //using mocks - only mockOne is interacted
     mockOne.add("one");
     //ordinary verification
     verify(mockOne).add("one");
     //verify that method was never called on a mock
     verify(mockOne, never()).add("two");
     //verify that other mocks were not interacted
     verifyZeroInteractions(mockTwo, mockThree);

    快速創建Mock對象

    public class ArticleManagerTest {
       @Mock private ArticleCalculator calculator;
          @Mock private ArticleDatabase database;
          @Mock private UserProvider userProvider;
          @Before
          public void before(){
              MockitoAnnotations.initMocks(this);
          }
    }

    自定義返回不同結果

    when(mock.someMethod("some arg"))
       .thenThrow(new RuntimeException())  // 第一次會拋出異常
       .thenReturn("foo"); // 第二次會返回這個結果
    //First call: throws runtime exception:
    mock.someMethod("some arg"); // 第一次
    //Second call: prints "foo"
    System.out.println(mock.someMethod("some arg")); // 第二次
    //Any consecutive call: prints "foo" as well (last stubbing wins).
    System.out.println(mock.someMethod("some arg")); // 第n次(n> 2),依舊以最后返回最后一個配置

    對返回結果進行攔截

    when(mock.someMethod(anyString())).thenAnswer(new Answer() {
        Object answer(InvocationOnMock invocation) {
            Object[] args = invocation.getArguments();
            Object mock = invocation.getMock();
            return "called with arguments: " + args;
        }
    });
    //the following prints "called with arguments: foo"
    System.out.println(mock.someMethod("foo"));

    Mock函數操作

    可以通過doThrow(), doAnswer(), doNothing(), doReturn() and doCallRealMethod() 來自定義函數操作。

    暗中調用真實對象

    List list = new LinkedList();
    List spy = spy(list);
    //optionally, you can stub out some methods:
    when(spy.size()).thenReturn(100);
    //using the spy calls *real* methods
    spy.add("one");
    spy.add("two");
    //prints "one" - the first element of a list
    System.out.println(spy.get(0));
    //size() method was stubbed - 100 is printed
    System.out.println(spy.size());
    //optionally, you can verify
    verify(spy).add("one");
       verify(spy).add("two");

    改變默認返回值

    Foo mock = mock(Foo.class, Mockito.RETURNS_SMART_NULLS);
    Foo mockTwo = mock(Foo.class, new YourOwnAnswer());

    捕獲函數的參數值

    ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
    verify(mock).doSomething(argument.capture());
    assertEquals("John", argument.getValue().getName());

    部分Mock

    //you can create partial mock with spy() method:
    List list = spy(new LinkedList());
    //you can enable partial mock capabilities selectively on mocks:
    Foo mock = mock(Foo.class);
    //Be sure the real implementation is 'safe'.
    //If real implementation throws exceptions or depends on specific state of the object then you're in trouble.
    when(mock.someMethod()).thenCallRealMethod();

    重置Mock

    List mock = mock(List.class);
    when(mock.size()).thenReturn(10);
    mock.add(1);
    reset(mock);
    //at this point the mock forgot any interactions & stubbing

    序列化

    List<Object> list = new ArrayList<Object>();
    List<Object> spy = mock(ArrayList.class, withSettings()
                     .spiedInstance(list)
                     .defaultAnswer(CALLS_REAL_METHODS)
                     .serializable());

    檢查超時

    //passes when someMethod() is called within given time span
    verify(mock, timeout(100)).someMethod();
    //above is an alias to:
    verify(mock, timeout(100).times(1)).someMethod();
    //passes when som`eMethod() is called *exactly* 2 times within given time span
    verify(mock, timeout(100).times(2)).someMethod();
    //passes when someMethod() is called *at least* 2 times within given time span
    verify(mock, timeout(100).atLeast(2)).someMethod();
    //verifies someMethod() within given time span using given verification mode
    //useful only if you have your own custom verification modes.
    verify(mock, new Timeout(100, yourOwnVerificationMode)).someMethod();

    Mock詳情

    Mockito.mockingDetails(someObject).isMock();
    Mockito.mockingDetails(someObject).isSpy();

     

    原文轉自:http://www.jianshu.com/p/77db26b4fb54

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>