310

我已经用谷歌搜索了这个,但没有找到任何相关的东西。我有这样的事情:

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

现在,我想验证mymethod(Object o)调用 insideruntestmethod()是使用 Object 调用的o,而不是任何其他调用。但我总是通过测试,无论我在验证中添加什么,例如:

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

或者

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

或者

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

我总是通过考试。我怎样才能完成该验证(如果可能)?

谢谢你。

4

11 回答 11

447

的替代方案ArgumentMatcherArgumentCaptor

官方示例:

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());
}
于 2015-08-19T08:22:19.163 回答
73

您是否尝试使用对象的 .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);

这将验证它被调用过一次。

于 2013-03-02T19:24:36.110 回答
67

argThat加拉姆达

这就是您无法通过论证验证的方式:

    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 期望您的验证器静默返回true参数 set 之一,并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'. 注意:我使用assertJ了断言,但使用哪个断言框架取决于您。


直接论证

Mokito 使用以下方法比较直接参数equals()

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

eq匹配器


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;

原始问题失败的根本原因是括号的错误位置:

  • verify(mock.mymethod.... 那是错误的。权利将是:
  • verify(mock).*
于 2019-07-31T00:03:38.657 回答
61
  • eq如果您不使用其他匹配器,则不需要匹配器。
  • 您没有使用正确的语法 - 您的方法调用应该在.verify(mock). 您现在正在对方法调用的结果进行验证,而不验证任何内容(不进行方法调用)。因此,所有测试都通过了。

您的代码应如下所示:

Mockito.verify(mock).mymethod(obj);
Mockito.verify(mock).mymethod(null);
Mockito.verify(mock).mymethod("something_else");
于 2010-08-24T10:36:32.263 回答
14

我以这种方式使用了 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
    }
}
于 2017-11-21T10:38:57.613 回答
5

您是否检查过可模拟类的 equals 方法?如果这个总是返回 true 或者你针对同一个实例测试同一个实例并且 equal 方法没有被覆盖(因此只检查引用),那么它返回 true。

于 2012-03-02T08:17:42.697 回答
4

另一种方法是使用 org.mockito.internal.matchers.Equals.Equals 方法而不是重新定义一个:

verify(myMock).myMethod((inputObject)Mockito.argThat(new Equals(inputObjectWanted)));
于 2016-03-08T06:26:27.200 回答
4

上面的许多答案让我感到困惑,但我怀疑这可能是由于旧版本的 Mockito 造成的。这个答案是使用完成的

  • 爪哇 11
  • 模拟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());
}
于 2020-09-21T21:15:38.637 回答
3

您是否尝试过使用相同的()匹配器?如:

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

我有同样的问题。我尝试使用 eq() 匹配器和 refEq() 匹配器,但我总是误报。当我使用 same() 匹配器时,当参数是不同的实例时测试失败,一旦参数是相同的实例,测试就会通过。

于 2015-07-03T17:29:01.883 回答
3
Verify(a).aFunc(eq(b))

在伪代码中:

当在实例中时a- 一个名为的函数aFunc被调用。

验证此调用是否有一个等于 的参数b

于 2020-07-21T22:41:49.477 回答
0

您还可以使用 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)));
于 2016-02-17T04:05:14.037 回答