簡體   English   中英

mockito驗證與ArgumentCaptor的交互

[英]mockito verify interactions with ArgumentCaptor

要檢查與模擬的交互次數,其中方法調用中的參數是某種類型,可以做

mock.someMethod(new FirstClass());
mock.someMethod(new OtherClass());
verify(mock, times(1)).someMethod(isA(FirstClass.class));

這將通過調用isA因為someMethod被調用兩次,但只有一次使用參數FirstClass

但是,使用ArgumentCaptor時,這種模式似乎是不可能的,即使Captor是為特定參數FirstClass創建的

這不起作用

mock.someMethod(new FirstClass());
mock.someMethod(new OtherClass());
ArgumentCaptor<FirstClass> captor = ArgumentCaptor.forClass(FirstClass.class);
verify(mock, times(1)).someMethod(captor.capture());

它說模擬不止一次被召喚。

在獲取進一步檢查的參數時,有沒有辦法完成此驗證?

我建議使用Mockito的Hamcrest集成為它編寫一個好的,干凈的匹配器。 這允許您將驗證與對傳遞參數的詳細檢查結合起來:

verify(mock, times(1)).someMethod(argThat(personNamed("Bob")));

Matcher<Person> personNamed(final String name) {
    return new TypeSafeMatcher<Person>() {
        public boolean matchesSafely(Person item) {
            return name.equals(item.getName());
        }
        public void describeTo(Description description) {
            description.appendText("a Person named " + name);
        }
    };
}

匹配器通常會導致更可讀的測試和更有用的測試失敗消息。 它們也往往是非常可重用的,你會發現自己建立了一個為測試你的項目量身定制的庫。 最后,您還可以使用JUnit的Assert.assertThat()將它們用於正常的測試斷言,因此您可以使用它們進行雙重使用。

引用文檔:

請注意, ArgumentCaptor 不進行任何類型檢查 ,只是為了避免在代碼中進行轉換。 但是,這可能會在未來的主要版本中發生變化(可以添加類型檢查)。

我不會為此使用ArgumentCaptor 這個類捕獲(字面上)所有內容,盡管提供了類的.forClass參數。

為了達到你想要的效果,我建議使用Mockito的Answer接口攔截參數:

private FirstClass lastArgument;

@Test
public void captureFirstClass() throws Exception {
    doAnswer(captureLastArgument()).when(mock).someMethod(anInstanceOfFirstClass());
    mock.someMethod(new FirstClass());
    mock.someMethod(new OtherClass());

    verify(mock, times(1)).someMethod(anInstanceOfFirstClass());
    //write your desired matchers against lastArgument object
}

private Answer<FirstClass> captureLastArgument() {
    return new Answer<FirstClass>() {
        @Override
        public FirstClass answer(InvocationOnMock invocation) throws Throwable {
            TestClass.this.lastArgument = (FirstClass) invocation.getArguments()[0];
            return null;
        }
    };
}

private static Object anInstanceOfFirstClass(){
    return Mockito.argThat(isA(FirstClass.class));
}

您可以使用捕獲器來捕獲,然后分別驗證每個參數類型的調用次數。

    // given
    ArgumentCaptor<AA> captor = ArgumentCaptor.forClass(AA.class);
    CC cc = new CC();
    // when
    cut.someMethod(new AA());
    cut.someMethod(new BB());
    cut.someMethod(new BB());
    cut.someMethod(cc);
    // then
    Mockito.verify(collaborator, atLeastOnce()).someMethod(captor.capture());
    Mockito.verify(collaborator, times(1)).someMethod(isA(AA.class));
    Mockito.verify(collaborator, times(2)).someMethod(isA(BB.class));
    Mockito.verify(collaborator, times(1)).someMethod(isA(CC.class));
    assertEquals(cc, captor.getValue());

顯然,captor引用的泛型類型不會影響運行時的任何內容。

我今天也遇到了這個問題。 我以為我可以簡單地做一些事情

verify(mock).someMethod(and(isA(FirstClass.class), captor.capture()));

但我無法讓它發揮作用。 我最終得到了這個解決方案:

@Test
public void Test() throws Exception {
    final ArgumentCaptor<FirstClass> captor = ArgumentCaptor.forClass(FirstClass.class);

    mock.someMethod(new FirstClass());
    mock.someMethod(new OtherClass());

    verify(eventBus, atLeastOnce()).post(captor.capture());
    final List<FirstClass> capturedValues = typeCheckedValues(captor.getAllValues(), FirstClass.class);
    assertThat(capturedValues.size(), is(1));
    final FirstClass capturedValue = capturedValues.get(0);
    // Do assertions on capturedValue
}

private static <T> List<T> typeCheckedValues(List<T> values, Class<T> clazz) {
    final List<T> typeCheckedValues = new ArrayList<>();
    for (final T value : values) {
        if (clazz.isInstance(value)) {
            typeCheckedValues.add(value);
        }
    }
    return typeCheckedValues;
}

注意:如果只需要以這種方式捕獲一個類,則typeCheckedValues可以簡化為:

private static List<FirstClass> typeCheckedValues(List<FirstClass> values) {
    final List<FirstClass> typeCheckedValues = new ArrayList<>();
    for (final Object value : values) {
        if (value instanceof FirstClass) {
            typeCheckedValues.add((FirstClass) value);
        }
    }
    return typeCheckedValues;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM