簡體   English   中英

莫基托。 驗證方法參數

[英]Mockito. Verify method arguments

我用谷歌搜索過這個,但沒有找到任何相關的東西。 我有這樣的事情:

Object obj = getObject();
Mockeable mock= Mockito.mock(Mockeable.class);
Mockito.when(mock.mymethod(obj )).thenReturn(null);

Testeable testableObj = new Testeable();
testableObj.setMockeable(mock);
command.runtestmethod();

現在,我想驗證在runtestmethod()內部調用的mymethod(Object o)是使用 Object o調用的,而不是其他任何方法。 但是我總是通過測試,無論我進行什么驗證,例如:

Mockito.verify(mock.mymethod(Mockito.eq(obj)));

要么

Mockito.verify(mock.mymethod(Mockito.eq(null)));

要么

Mockito.verify(mock.mymethod(Mockito.eq("something_else")));

我總是通過考試。 我如何完成該驗證(如果可能)?

謝謝你。

ArgumentMatcher的替代品是ArgumentCaptor

官方示例:

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

還可以使用@Captor注釋定義捕獲器:

@Captor ArgumentCaptor<Person> captor;
//... MockitoAnnotations.initMocks(this);
@Test public void test() {
    //...
    verify(mock).doSomething(captor.capture());
    assertEquals("John", captor.getValue().getName());
}

您是否嘗試使用對象的 .equals 方法進行邏輯相等? 您可以使用 Mockito 中包含的 argThat 匹配器來執行此操作

import static org.mockito.Matchers.argThat

接下來,您可以實現自己的參數匹配器,該匹配器將遵循每個對象的 .equals 方法

private class ObjectEqualityArgumentMatcher<T> extends ArgumentMatcher<T> {
    T thisObject;

    public ObjectEqualityArgumentMatcher(T thisObject) {
        this.thisObject = thisObject;
    }

    @Override
    public boolean matches(Object argument) {
        return thisObject.equals(argument);
    }
}

現在使用您的代碼,您可以更新它以閱讀...

Object obj = getObject();
Mockeable mock= Mockito.mock(Mockeable.class);
Mockito.when(mock.mymethod(obj)).thenReturn(null);

Testeable obj = new Testeable();
obj.setMockeable(mock);
command.runtestmethod();

verify(mock).mymethod(argThat(new ObjectEqualityArgumentMatcher<Object>(obj)));

如果你只是想要完全相等(內存中的同一個對象),那就做

verify(mock).mymethod(obj);

這將驗證它是否被調用過一次。

  • 如果您不使用其他匹配器,則不需要eq匹配器。
  • 您沒有使用正確的語法 - 您的方法調用應該在.verify(mock) 您現在正在對方法調用的結果進行驗證,而不驗證任何內容(不進行方法調用)。 因此,所有測試都通過了。

您的代碼應如下所示:

Mockito.verify(mock).mymethod(obj);
Mockito.verify(mock).mymethod(null);
Mockito.verify(mock).mymethod("something_else");

argThat加上 lambda

這就是您無法通過參數驗證的方式:

    verify(mock).mymethod(argThat(
      (x)->false
    ));

在哪里

import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;

argThat加上斷言

上面的測試會“說” Expected: lambda$... Was: YourClass.toSting... 如果在 lambda 中使用斷言,您可以獲得更具體的失敗原因:

    verify(mock).mymethod(argThat( x -> {
      assertThat(x).isNotNull();
      assertThat(x.description).contains("KEY");
      return true;
    }));

❗️但是❗️:這僅在

  • 呼叫預計 1 次,或
  • 預計調用 2+ 次,但驗證器匹配的所有時間(返回true )。

如果已驗證的方法調用了 2+ 次,mockito 會將所有調用的組合傳遞給每個驗證器。 因此, mockito 期望您的驗證器靜默地為參數 set 之一返回true ,並為其他有效調用返回false (無斷言異常)。 這種期望對於 1 次方法調用來說不是問題 - 它應該只返回 true 1 次。

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;

現在失敗的測試會說: Expected: Obj.description to contain 'KEY'. Was: 'Actual description' Expected: Obj.description to contain 'KEY'. Was: 'Actual description' 注意:我使用了assertJ斷言,但使用哪個斷言框架取決於您。


argThat帶有多個參數。

如果您使用argThat ,則必須為所有參數提供匹配項。 例如,如果您有另一個帶有 2 個參數的方法:

    verify(mock).mymethod2(eq("VALUE_1"), argThat((x)->false));
    // above is correct as eq() is also an argument matcher.

verify(mock).mymethod2("VALUE_1", argThat((x)->false));

// above is incorrect; an exception will be thrown, as the first arg. is given without an argument matcher.

在哪里:

import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;

eq

檢查參數是否相等的最簡單方法:

verify(mock).mymethod(eq(expectedValue));
// NOTE:   ^ where the parentheses must be closed.

直接論證

如果通過 ref 進行比較是可以接受的,那么繼續:

verify(mock).mymethod(expectedArg);
// NOTE:   ^ where the parentheses must be closed.

原始問題失敗的verify(mock.mymethod...原因是括號的錯誤位置: verify(mock.mymethod...那是錯誤的。正確的是: verify(mock).*

我以這種方式使用了 Mockito.verify

@UnitTest
public class JUnitServiceTest
{
    @Mock
    private MyCustomService myCustomService;


    @Test
    public void testVerifyMethod()
    {
       Mockito.verify(myCustomService, Mockito.never()).mymethod(parameters); // method will never call (an alternative can be pick to use times(0))
       Mockito.verify(myCustomService, Mockito.times(2)).mymethod(parameters); // method will call for 2 times
       Mockito.verify(myCustomService, Mockito.atLeastOnce()).mymethod(parameters); // method will call atleast 1 time
       Mockito.verify(myCustomService, Mockito.atLeast(2)).mymethod(parameters); // method will call atleast 2 times
       Mockito.verify(myCustomService, Mockito.atMost(3)).mymethod(parameters); // method will call at most 3 times
       Mockito.verify(myCustomService, Mockito.only()).mymethod(parameters); //   no other method called except this
    }
}

您是否檢查過可模擬類的 equals 方法? 如果這個總是返回 true 或者你針對同一個實例測試同一個實例並且 equal 方法沒有被覆蓋(因此只檢查引用),那么它返回 true。

另一種方法是使用 org.mockito.internal.matchers.Equals.Equals 方法而不是重新定義一個:

verify(myMock).myMethod((inputObject)Mockito.argThat(new Equals(inputObjectWanted)));

您是否嘗試過使用 same() 匹配器? 如:

verify(mockObj).someMethod(same(specificInstance));

我有同樣的問題。 我用 eq() 匹配器和 refEq() 匹配器嘗試過,但我總是有誤報。 當我使用 same() 匹配器時,當參數是不同的實例時測試失敗,並且一旦參數是相同的實例就通過了。

Verify(a).aFunc(eq(b))

在偽代碼中:

在實例a - 調用名為aFunc的函數時。

驗證此調用有一個等於b的參數。

上述許多答案讓我感到困惑,但我懷疑這可能是由於舊版本的 Mockito。 這個答案是使用完成的

  • 爪哇 11
  • Mockito 3.1.0
  • SpringBoot 2.2.7.RELEASE
  • JUnit5

使用 ArgumentCaptor 我是這樣做的:

@Mock
MyClientService myClientService;
@InjectMocks 
MyService myService;


@Test
void myTest() {

  ArgumentCaptor<String> captorParam1 = ArgumentCaptor.forClass(String.class);
  ArgumentCaptor<String> captorParam2 = ArgumentCaptor.forClass(String.class);

  Mockito.when(myClientService.doSomething(captorParam1.capture(), captorParam2.capture(), ArgumentMatchers.anyString()))
      .thenReturn(expectedResponse);

  assertDoesNotThrow(() -> myService.process(data));

  assertEquals("param1", captorParam1.getValue());
  assertEquals("param2", captorParam2.getValue());

  verify(myClientService, times(1))
    .doSomething(anyString(), anyString(), anyString());
}

您還可以使用 TypeSafeDiagnosingMatcher

    private Matcher<GetPackagesRequest> expectedPackageRequest(final AvailabilityRequest request) {
    return new TypeSafeDiagnosingMatcher<GetPackagesRequest>() {

        StringBuilder text = new StringBuilder(500);

        @Override
        protected boolean matchesSafely(GetPackagesRequest req, Description desc) {
            String productCode = req.getPackageIds().iterator().next().getValue();
            if (productCode.equals(request.getSupplierProductCode())) {
                text.append("ProductCode not equal! " + productCode + " , " + request.getSupplierProductCode());
                return true;
            }

            text.append(req.toString());
            return false;
        }

        @Override
        public void describeTo(Description d) {
            d.appendText(text.toString());
        }
    };
}

然后驗證該調用:

Mockito.verify(client).getPackages(Mockito.argThat(expectedPackageRequest(request)));

暫無
暫無

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

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