Java 莫基托。验证方法参数

Java 莫基托。验证方法参数,java,unit-testing,junit,mockito,Java,Unit Testing,Junit,Mockito,我在谷歌上搜索过这件事,但没有找到任何相关信息。我有这样的想法: Object obj = getObject(); Mockeable mock= Mockito.mock(Mockeable.class); Mockito.when(mock.mymethod(obj )).thenReturn(null); Testeable testableObj = new Testeable(); testableObj.setMockeable(mock); command.runtestmet

我在谷歌上搜索过这件事,但没有找到任何相关信息。我有这样的想法:

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

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

谢谢。

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

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

你检查过mockable类的equals方法了吗?如果此方法返回always true,或者您针对同一实例测试同一实例,并且equal方法未被覆盖(因此仅针对引用进行检查),那么它将返回true。

是否尝试使用对象的.equals方法执行逻辑相等?您可以利用Mockito中包含的argThat matcher来实现这一点

import static org.mockito.Matchers.argThat
接下来,您可以实现自己的参数匹配器,它将遵从每个objects.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);
    }
}

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

是否使用相同的()匹配器进行了尝试?例如:

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

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

作为
ArgumentMatcher
的替代方法是

官方示例:

ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
verify(mock).doSomething(argument.capture());
assertEquals("John", argument.getValue().getName());
ArgumentCaptor argument=ArgumentCaptor.forClass(Person.class);
验证(mock).doSomething(argument.capture());
assertEquals(“John”,argument.getValue().getName());
也可以使用注释定义捕获者:

@Captor ArgumentCaptor<Person> captor;
//... MockitoAnnotations.initMocks(this);
@Test public void test() {
    //...
    verify(mock).doSomething(captor.capture());
    assertEquals("John", captor.getValue().getName());
}
@Captor ArgumentCaptor Captor Captor;
//... initMocks(this);
@测试公共无效测试(){
//...
验证(mock).doSomething(captor.capture());
assertEquals(“John”,captor.getValue().getName());
}

您也可以使用类型安全诊断匹配器

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

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

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

我用这种方式使用了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
    }
}
argThat
plus lambda 这就是你无法通过论证验证的原因:

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


argThat
plus断言 上述测试将“显示”
预期值: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
(无断言异常)。对于1个方法调用来说,这种期望不是问题——它应该只返回true 1次

现在失败的测试将显示:
预期:Obj.description包含“KEY”。Was:“实际描述”
。注意:我使用了
assertJ
asserts,但是使用哪种断言框架取决于您


arg包含多个参数。
如果使用
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))

//以上内容不正确;当第一个arg时,将抛出一个exceptoin。在没有参数匹配器的情况下给出。

其中:

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

eq
matcher 检查参数是否相等的最简单方法是:

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

直接论点 如果可以通过ref进行比较,则继续:

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

原始问题失败的根本原因是问题的错误位置:
验证(mock.mymethod…
。这是错误的。正确的答案是:
验证(mock)。*

在伪代码中:

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

验证此调用获得的参数是否等于
b


上面的许多答案让我感到困惑,但我怀疑这可能是因为Mockito的旧版本

  • 爪哇11
  • Mockito 3.1.0
  • SpringBoot 2.2.7.1版本
  • 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());
}
@Mock
MyClientService MyClientService;
@注射模拟
我的服务我的服务;
@试验
void myTest(){
ArgumentCaptor captorParam1=ArgumentCaptor.forClass(String.class);
ArgumentCaptor captorParam2=ArgumentCaptor.forClass(String.class);
Mockito.when(myClientService.doSomething(captorParam1.capture()、captorParam2.capture()、ArgumentMatchers.anyString())
.然后返回(预期响应);
AssertDoethrow(()->myService.process(数据));
assertEquals(“param1”,captorParam1.getValue());
assertEquals(“param2”,captorParam2.getValue());
验证(myClientService,次数(1))
.doSomething(anyString(),anyString(),anyString());
}

我以前试过,现在又试过了。我仍然有同样的问题,测试总是通过。它通过引用验证您可以使用内置的
ReflectionEquals
类来实现此目的。+1作为您的答案。但是我想补充一点
验证(mock).mymethod(obj);
不会检查是否完全相等(内存中的同一对象)。相反,它使用
    verify(mock).mymethod(argThat( x -> {
      assertThat(x).isNotNull();
      assertThat(x.description).contains("KEY");
      return true;
    }));
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;
    verify(mock).mymethod(eq("VALUE_1"), argThat((x)->false));
    // above is correct as eq() is also an argument matcher.
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
verify(mock).mymethod(eq(expectedValue));
// NOTE:   ^ where the parentheses must be closed.
verify(mock).mymethod(expectedArg);
// NOTE:   ^ where the parentheses must be closed.
Verify(a).aFunc(eq(b))
@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());
}