BDDMockito 風格

行為驅動開發(BDD)測試風格圍繞測試中的給定何時然後階段。然而,經典的 Mockito 將 when 單詞用於給定階段,並且不包括可以包含 BDD 的其他自然語言結構。因此,在 1.8.0 版本中引入了 BDDMockito 別名,以便於行為驅動的測試。

最常見的情況是存根方法的返回。在下面的示例中,如果使用等於 givenName 的引數呼叫,則模擬 StudentRepositorygetStudent(String) 方法將返回 new Student(givenName, givenScore)

import static org.mockito.BDDMockito.*;

public class ScoreServiceTest {

    private StudentRepository studentRepository = mock(StudentRepository.class);

    private ScoreService objectUnderTest = new ScoreService(studentRepository);

    @Test
    public void shouldCalculateAndReturnScore() throws Exception {
        //given
        String givenName = "Johnny";
        int givenScore = 10;
        given(studentRepository.getStudent(givenName))
            .willReturn(new Student(givenName, givenScore));

        //when
        String actualScore = objectUnderTest.calculateStudentScore(givenName);

        //then
        assertEquals(givenScore, actualScore);
    }
}

有時需要檢查從依賴項丟擲的異常是否在被測試的方法中正確處理或重新丟擲。這樣的行為可以通過這種方式在給定階段中存根:

willThrow(new RuntimeException())).given(mock).getData();

有時需要設定一些存根方法應該引入的副作用。特別是它可以派上用場:

  • stubbed 方法是一種應該改變傳遞物件的內部狀態的方法

  • stubbed 方法是一種 void 方法

這種行為可以在給定階段以答案存根:

willAnswer(invocation -> this.prepareData(invocation.getArguments()[0])).given(mock).processData();

當需要驗證與模擬的互動時,可以使用 should()should(VerificationMode)(僅自 1.10.5)方法在 then 階段完成:

then(mock).should().getData(); // verifies that getData() was called once
then(mock).should(times(2)).processData(); // verifies that processData() was called twice

當需要驗證除了已經驗證之外沒有更多與模擬的互動時,可以使用 shouldHaveNoMoreInteractions()(從 2.0.0 開始)在 then 階段完成:

then(mock).shouldHaveNoMoreInteractions(); // analogue of verifyNoMoreInteractions(mock) in classical Mockito

當需要驗證絕對沒有與 mock 的互動時,可以使用 shouldHaveNoMoreInteractions()(從 2.0.0 開始)在 then 階段完成:

then(mock).shouldHaveZeroInteractions(); // analogue of verifyZeroInteractions(mock) in classical Mockito

當需要檢查方法是否被呼叫時 ,可以在 then 階段使用 should(InOrder)(自 1.10.5 起)和 should(InOrder, VerificationMode)(自 2.0.0 起)完成:

InOrder inOrder = inOrder(mock);

// test body here

then(mock).should(inOrder).getData(); // the first invocation on the mock should be getData() invocation
then(mock).should(inOrder, times(2)).processData(); // the second and third invocations on the mock should be processData() invocations