307

I have a method call which I want to mock with mockito. To start with I have created and injected an instance of an object on which the method will be called. My aim is to verify one of the object in method call.

Is there a way that mockito allows you to assert or verify the object and it's attributes when the mock method is called?

example

Mockito.verify(mockedObject)
       .someMethodOnMockedObject(
              Mockito.<SomeObjectAsArgument>anyObject())

Instead of doing anyObject() i want to check that argument object contains some particular fields

Mockito.verify(mockedObject)
       .someMethodOnMockedObject(
              Mockito.<SomeObjectAsArgument>**compareWithThisObject()**)
4

11 回答 11

614

添加到 Mockito 的新功能使这变得更加容易,

ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
verify(mock).doSomething(argument.capture());
assertEquals("John", argument.getValue().getName());

查看 Mockito文档


如果有多个参数,并且只需要捕获单个参数,请使用其他 ArgumentMatchers 包装其余参数:

verify(mock).doSomething(eq(someValue), eq(someOtherValue), argument.capture());
assertEquals("John", argument.getValue().getName());
于 2011-09-15T20:09:39.907 回答
74

我认为验证参数对象的最简单方法是使用以下refEq方法:

Mockito.verify(mockedObject).someMethodOnMockedObject(ArgumentMatchers.refEq(objectToCompareWith));

即使对象没有实现也可以使用它equals(),因为使用了反射。如果您不想比较某些字段,只需将它们的名称添加为refEq.

于 2014-05-30T08:38:51.827 回答
54

如果您不想使用ArgumentCaptor(例如,因为您也在使用存根),另一种可能性是将 Hamcrest Matchers 与 Mockito 结合使用。

import org.mockito.Mockito
import org.hamcrest.Matchers
...

Mockito.verify(mockedObject).someMethodOnMockedObject(MockitoHamcrest.argThat(
    Matchers.<SomeObjectAsArgument>hasProperty("propertyName", desiredValue)));
于 2012-05-01T00:17:19.430 回答
20

这是基于iraSenthil 的答案但带有注释 ( Captor ) 的答案。在我看来,它有一些优点:

  • 它更短
  • 更容易阅读
  • 它可以在没有警告的情况下处理泛型

例子:

@RunWith(MockitoJUnitRunner.class)
public class SomeTest{

    @Captor
    private ArgumentCaptor<List<SomeType>> captor;

    //...

    @Test 
    public void shouldTestArgsVals() {
        //...
        verify(mockedObject).someMethodOnMockedObject(captor.capture());

        assertThat(captor.getValue().getXXX(), is("expected"));
    }
}
于 2015-04-09T15:07:59.053 回答
11

如果您使用的是 Java 8,则可以使用 Lambda 表达式进行匹配。

import java.util.Optional;
import java.util.function.Predicate;

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;

public class LambdaMatcher<T> extends BaseMatcher<T>
{
    private final Predicate<T> matcher;
    private final Optional<String> description;

    public LambdaMatcher(Predicate<T> matcher)
    {
        this(matcher, null);
    }

    public LambdaMatcher(Predicate<T> matcher, String description)
    {
        this.matcher = matcher;
        this.description = Optional.ofNullable(description);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean matches(Object argument)
    {
        return matcher.test((T) argument);
    }

    @Override
    public void describeTo(Description description)
    {
        this.description.ifPresent(description::appendText);
    }
}

示例调用

@Test
public void canFindEmployee()
{
    Employee employee = new Employee("John");
    company.addEmployee(employee);

    verify(mockedDal).registerEmployee(argThat(new LambdaMatcher<>(e -> e.getName()
                                                                         .equals(employee.getName()))));
}

更多信息:http: //source.coveo.com/2014/10/01/java8-mockito/

于 2016-03-17T19:56:06.973 回答
10

一个简化的解决方案,无需创建新的 Matcher 实现类并使用 lambda 表达式:

verify(mockObject).someMockMethod(
        argThat((SomeArgument arg) -> arg.fieldToMatch.equals(expectedFieldValue)));
于 2020-06-19T09:59:15.357 回答
6

上面的解决方案在我的情况下并没有真正起作用。我无法使用 ArgumentCaptor,因为该方法被调用了多次,我需要验证每一个。一个带有“argThat”的简单匹配器很容易做到这一点。

自定义匹配器

// custom matcher
private class PolygonMatcher extends ArgumentMatcher<PolygonOptions> {
    private int fillColor;
    public PolygonMatcher(int fillColor) {
        this.fillColor = fillColor;
    }

    @Override
    public boolean matches(Object argument) {
        if (!(argument instanceof PolygonOptions)) return false;
        PolygonOptions arg = (PolygonOptions)argument;
        return Color.red(arg.getFillColor()) == Color.red(fillColor)
                && Color.green(arg.getFillColor()) == Color.green(fillColor)
                && Color.blue(arg.getFillColor()) == Color.blue(fillColor);
    }
}

测试赛跑者

// do setup work setup
// 3 light green polygons
int green = getContext().getResources().getColor(R.color.dmb_rx_bucket1);
verify(map, times(3)).addPolygon(argThat(new PolygonMatcher(green)));

// 1 medium yellow polygons
int yellow = getContext().getResources().getColor(R.color.dmb_rx_bucket4);
    verify(map, times(1)).addPolygon(argThat(new PolygonMatcher(yellow)));

// 3 red polygons
int orange = getContext().getResources().getColor(R.color.dmb_rx_bucket5);
verify(map, times(3)).addPolygon(argThat(new PolygonMatcher(orange)));

// 2 red polygons
int red = getContext().getResources().getColor(R.color.dmb_rx_bucket7);
verify(map, times(2)).addPolygon(argThat(new PolygonMatcher(red)));
于 2017-11-09T22:41:48.530 回答
3

在 koltin 中非常漂亮和干净的解决方案来自com.nhaarman.mockito_kotlin

verify(mock).execute(argThat {
    this.param = expected
})
于 2018-12-06T11:01:04.437 回答
1

refEq 的 javadoc 提到相等性检查很浅!您可以在以下链接中找到更多详细信息:

https://static.javadoc.io/org.mockito/mockito-core/2.2.29/org/mockito/ArgumentMatchers.html#refEq(T,%20java.lang.String...)

当您使用其他未实现 .equals() 方法的类时,无法控制“浅相等”问题,“DefaultMongoTypeMapper”类是未实现 .equals() 方法的示例。

org.springframework.beans.factory.support 提供了一种可以生成 bean 定义而不是创建对象实例的方法,它可以用来消除比较失败。

 genericBeanDefinition(DefaultMongoTypeMapper.class)
                        .setScope(SCOPE_SINGLETON)
                        .setAutowireMode(AUTOWIRE_CONSTRUCTOR)
                        .setLazyInit(false)
                        .addConstructorArgValue(null)
                        .getBeanDefinition()

**“bean 定义只是对 bean 的描述,而不是 bean 本身。bean 描述正确地实现了 equals() 和 hashCode(),因此我们提供了一个定义来告诉 spring 它是如何实现的,而不是创建一个新的 DefaultMongoTypeMapper()应该创造一个”

在您的示例中,您可以这样做

Mockito.verify(mockedObject)
       .doSoething(genericBeanDefinition(YourClass.class).setA("a")
       .getBeanDefinition());
于 2017-02-25T06:12:53.270 回答
1

您可以参考以下内容:

Mockito.verify(mockedObject).someMethodOnMockedObject(eq(desiredObject))

这将验证是否以 desiredObject 作为参数调用了 mockedObject 的方法。

于 2016-12-07T13:05:08.697 回答
1

另一种简单的方法:

import org.mockito.BDDMockito;    
import static org.mockito.Matchers.argThat;
import org.mockito.ArgumentMatcher;

BDDMockito.verify(mockedObject)
        .someMethodOnMockedObject(argThat(new ArgumentMatcher<TypeOfMethodArg>() {

            @Override
            public boolean matches(Object argument) {
                final TypeOfMethodArg castedArg = (TypeOfMethodArg) argument;

                // Make your verifications and return a boolean to say if it matches or not
                boolean isArgMarching = true;

                return isArgMarching;
            }
        }));
于 2019-02-13T16:00:04.697 回答