Mockito。验证方法参数


220

我已经对此进行了谷歌搜索,但是没有发现任何相关信息。我有这样的事情:

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()调用了,是通过Object调用的o,而不是其他对象。但是无论我进行哪种验证,我都会始终通过测试,例如:

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

要么

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

要么

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

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

谢谢。

Answers:


333

的替代品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());
}

1
谢谢样品!没用过。在代码中包含诸如captor之类的东西有点奇怪,但这很有帮助。
Artemis

1
哈哈,我不明白这个问题,但是答案对我有很大帮助。谢谢:-)
Marcus K.

13
重要提示:使用模拟程序后,请调用verify()/ capture()。我本以为必须在“安装”之前...
Daniel Alder

1
感谢您的回答!
Jose Flavio QuispeIrrazábal19年

这是一个很好的答案!非常感谢你!
Ulky Igor

61

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

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


1
您可以ReflectionEquals为此目的使用内置类。
takacsot

2
+1为您的答案。但我想补充一点,就是verify(mock).mymethod(obj);不检查EXACT是否相等(内存中的同一对象)。相反,它使用可能被重写的对象equals-method。
efux

您还可以创建一个匿名实现,ArgumentMatcher以减少繁琐的工作。
botchniaque's

1
详细信息:默认情况下,verify()调用/ inbound参数的/ equals()方法,而不是/ recorded对象的/ equals()方法。除非您试图确认您的测试主题返回一个特定的对象实例,并且该主题返回的是该实例的透明装饰器,否则这无关紧要。该verify论点equals()不会知道装饰器。而装饰者的作品equals()将被改写以容忍原始作品。在这种情况下,您的测试将错误地失败。
Mark McKenna

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

您的代码应如下所示:

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

我曾经尝试过,现在再试一次。我仍然有同样的问题,测试总是通过。
manolowar

2
通过引用它是真实的
cnexans

16

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次以上,则Mockito将所有调用的组合传递给每个验证程序。因此,mockito期望您的验证程序以静默方式返回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'。注意:我使用了assertJ断言,但是要取决于您使用哪个断言框架。


argThat 有多个参数。

如果使用argThat,则必须为所有参数提供匹配项。例如:

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

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

// above is incorrect; an exceptoin will be thrown, as the fist 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).*


1
这是我最喜欢的答案,效果比其他答案好得多。
Airwavezx

11

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

5

您是否检查过可模仿类的equals方法?如果此方法始终返回true,或者您针对同一实例测试了同一实例,并且equal方法未被覆盖(因此仅针对引用进行检查),则它返回true。


4

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

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

3

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

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

我有同样的问题。我使用eq()匹配器和refEq()匹配器进行了尝试,但我总是遇到误报。当我使用same()匹配器时,如果参数是不同的实例,则测试失败,并且一旦参数是相同的实例,则通过。


-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)));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.