的Mockito。验证方法参数

时间:2010-08-24 10:27:54

标签: java unit-testing junit mockito

我用Google搜索了这个,但没有发现任何相关内容。我有这样的事情:

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)是否在runtestmethod()内调用,是使用对象o调用的,而不是其他任何调用。但是我总是通过测试,无论我在验证上做什么,例如:

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

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

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

我总是通过考试。如何完成验证(如果可能)?

谢谢。

11 个答案:

答案 0 :(得分:244)

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

答案 1 :(得分:56)

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

如果你只是想要EXACT相等(内存中的同一个对象),那就去做

verify(mock).mymethod(obj);

这将验证它被调用一次。

答案 2 :(得分:46)

  • 如果您不使用其他匹配器,则不需要eq匹配器。
  • 您没有使用正确的语法 - 您的方法调用应该在.verify(mock)之外。您现在正在启动对方法调用结果的验证,而不验证任何内容(不进行方法调用)。因此,所有测试都在通过。

您的代码应如下所示:

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

答案 3 :(得分:6)

这就是使参数验证失败的方法:

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

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

在您的特定情况下,最好使用ArgumentMatcher.eq,这样您的失败消息会提供更多信息,例如:Argument(s) are different! Wanted: mock.mymethod(Object_o); Actual invocation has different arguments: mock.mymethod("SOME_OTHER_OBJECT");

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

    ...
    Object o = getObject();
    ...
    verify(mock).mymethod(
                        eq(o)
                        );

答案 4 :(得分:4)

您是否检查了可模拟类的equals方法?如果这个返回总是为true,或者你对同一个实例测试相同的实例,并且不覆盖equal方法(因此只检查引用),则返回true。

答案 5 :(得分:4)

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

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

答案 6 :(得分:4)

我以这种方式使用过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
    }
}

答案 7 :(得分:2)

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

使用伪代码:

在实例a中,将调用名为aFunc的函数。

验证此调用是否得到一个等于b的参数。

答案 8 :(得分:1)

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

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

我遇到了同样的问题。我尝试使用eq()匹配器和refEq()匹配器,但我总是有误报。当我使用相同的()匹配器时,当参数是不同的实例时测试失败,并且一旦参数是同一个实例就传递。

答案 9 :(得分:0)

许多上述答案使我感到困惑,但我怀疑这可能是由于Mockito的旧版本所致。这个答案是使用

完成的
  • Java 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());
}

答案 10 :(得分:-1)

您也可以使用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)));