5。验证方法参数

我在谷歌上搜索了一下,但没有找到任何相关信息。我得到了这样的东西:

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)是用对象o调用的,而不是其他对象。但我总能通过测试,不管我用什么来验证,比如:

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

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

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

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

谢谢你!

401544 次浏览
  • 如果你不使用其他匹配器,你就不需要eq匹配器。
  • 你没有使用正确的语法-你的方法调用应该在.verify(mock)之外。您现在正在对方法调用的结果发起验证,而没有验证任何东西(没有进行方法调用)。因此所有测试都通过了。

你的代码应该是这样的:

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

你检查过mockable类的equals方法了吗?如果这个方法总是返回true,或者你对同一个实例测试同一个实例,而equal方法没有被覆盖(因此只检查引用),那么它返回true。

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

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

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

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

我也有同样的问题。我尝试了eq()匹配器以及refEq()匹配器,但我总是有误报。当我使用相同的()匹配器时,当参数是不同的实例时测试失败,当参数是相同的实例时测试通过。

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

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

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

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

我用过Mockito。以这种方式验证

@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
}
}

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,并对其他有效调用返回false(无断言异常)。这种期望对于一个方法调用来说不是问题——它应该只返回true一次。

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).* < / >强
Verify(a).aFunc(eq(b))

在伪代码:

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

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

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

  • Java 11
  • 5 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());
}