使用mockito验证对象属性值

发布于 2024-07-27 04:58:51 字数 515 浏览 4 评论 0原文

我有一个方法调用,我想用mockito 来模拟它。 首先,我创建并注入了一个将在其上调用该方法的对象实例。 我的目的是验证方法调用中的对象之一。

有没有一种方法可以让您在调用模拟方法时断言或验证对象及其属性?

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

我想检查参数对象是否包含一些特定字段,而不是执行 anyObject()

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

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()**)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

番薯 2024-08-03 04:58:51

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

New feature added to Mockito makes this even easier,

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

Take a look at Mockito documentation


In case when there are more than one parameters, and capturing of only single param is desired, use other ArgumentMatchers to wrap the rest of the arguments:

verify(mock).doSomething(eq(someValue), eq(someOtherValue), argument.capture());
assertEquals("John", argument.getValue().getName());
邮友 2024-08-03 04:58:51

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

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

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

I think the easiest way for verifying an argument object is to use the refEq method:

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

It can be used even if the object doesn't implement equals(), because reflection is used. If you don't want to compare some fields, just add their names as arguments for refEq.

你怎么这么可爱啊 2024-08-03 04:58:51

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

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

Mockito.verify(mockedObject).someMethodOnMockedObject(MockitoHamcrest.argThat(
    Matchers.<SomeObjectAsArgument>hasProperty("propertyName", desiredValue)));

One more possibility, if you don't want to use ArgumentCaptor (for example, because you're also using stubbing), is to use Hamcrest Matchers in combination with Mockito.

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

Mockito.verify(mockedObject).someMethodOnMockedObject(MockitoHamcrest.argThat(
    Matchers.<SomeObjectAsArgument>hasProperty("propertyName", desiredValue)));
南汐寒笙箫 2024-08-03 04:58:51

这是基于 来自 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"));
    }
}

This is answer based on answer from iraSenthil but with annotation (Captor). In my opinion it has some advantages:

  • it's shorter
  • it's easier to read
  • it can handle generics without warnings

Example:

@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"));
    }
}
壹場煙雨 2024-08-03 04:58:51

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

verify(mockObject).someMockMethod(
        argThat((SomeArgument arg) -> arg.fieldToMatch.equals(expectedFieldValue)));

A simplified solution, without creating a new Matcher implementation class and using lambda expression:

verify(mockObject).someMockMethod(
        argThat((SomeArgument arg) -> arg.fieldToMatch.equals(expectedFieldValue)));
贵在坚持 2024-08-03 04:58:51

如果您使用的是 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/

If you're using Java 8, you can use Lambda expressions to match.

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

Example call

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

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

More info: http://source.coveo.com/2014/10/01/java8-mockito/

风情万种。 2024-08-03 04:58:51

上面的解决方案对我来说并没有真正起作用。 我无法使用 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)));

The solutions above didn't really work in my case. I couldn't use ArgumentCaptor as the method was called several times and I needed to validate each one. A simple Matcher with "argThat" did the trick easily.

Custom Matcher

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

Test Runner

// 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)));
分開簡單 2024-08-03 04:58:51

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

verify(mock).execute(argThat {
    this.param = expected
})

And very nice and clean solution in koltin from com.nhaarman.mockito_kotlin

verify(mock).execute(argThat {
    this.param = expected
})
陪你搞怪i 2024-08-03 04:58:51

我一直在一个设置中工作,我们使用方法实例化了模拟服务类。 如果我想验证一个方法是否被调用了 1 次,并且对象参数在字段中包含特定值,那么我将如何执行此操作,对于 class Service,使用方法updateMethod(UpdateObject updateObjectParam){}

@Mock
Service service;

...

Mockito.verify(service, times(1)).updateMethod(argThat(updateParamObject -> updateParamObject.getField().equals("fieldValue")));

I've been working in a setup where we have instantized mocked service classes, with methods. And if I want to verify that a method has been called exactly 1 time, with an object parameter that contains a specific value in a field, here is how I would do it, for class Service, with method updateMethod(UpdateObject updateObjectParam){} :

@Mock
Service service;

...

Mockito.verify(service, times(1)).updateMethod(argThat(updateParamObject -> updateParamObject.getField().equals("fieldValue")));
只为守护你 2024-08-03 04:58:51

您可以参考以下内容:

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

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

You can refer the following:

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

This will verify whether method of mockedObject is called with desiredObject as parameter.

南城旧梦 2024-08-03 04:58:51

另一种简单的方法是:

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

Another easy way to do so:

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;
            }
        }));
水波映月 2024-08-03 04:58:51

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(),因此我们不是创建一个新的 DefaultMongoTypeMapper(),而是提供一个定义来告诉 spring 如何创建一个“

在您的示例中,您可以执行类似这样的操作

Mockito.verify(mockedObject)
       .doSoething(genericBeanDefinition(YourClass.class).setA("a")
       .getBeanDefinition());

The javadoc for refEq mentioned that the equality check is shallow! You can find more details at the link below:

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

"shallow equality" issue cannot be controlled when you use other classes which don't implement .equals() method,"DefaultMongoTypeMapper" class is an example where .equals() method is not implemented.

org.springframework.beans.factory.support offers a method that can generate a bean definition instead of creating an instance of the object, and it can be used to git rid of Comparison Failure.

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

**"The bean definition is only a description of the bean, not a bean itself.
the bean descriptions properly implement equals() and hashCode(), so rather than creating a new DefaultMongoTypeMapper() we provide a definition that tells spring how it should create one"

In your example, you can do somethong like this

Mockito.verify(mockedObject)
       .doSoething(genericBeanDefinition(YourClass.class).setA("a")
       .getBeanDefinition());
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文