Java 使用mockito验证对象属性值

Java 使用mockito验证对象属性值,java,mocking,mockito,Java,Mocking,Mockito,我有一个方法调用,我想用mockito模拟它。首先,我创建并注入了一个对象的实例,该对象将被调用该方法。我的目标是验证方法调用中的一个对象 调用mock方法时,mockito是否允许您断言或验证对象及其属性 范例 Mockito.verify(mockedObject) .someMethodOnMockedObject( Mockito.<SomeObjectAsArgument>anyObject()) Mockito增加的新功能使这更

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

调用mock方法时,mockito是否允许您断言或验证对象及其属性

范例

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

Mockito增加的新功能使这更容易

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

如果您不想使用
ArgumentCaptor
(例如,因为您也在使用存根),还有一种可能性是将Hamcrest匹配器与Mockito结合使用

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

Mockito.verify(mockedObject).someMethodOnMockedObject(MockitoHamcrest.argThat(
    Matchers.<SomeObjectAsArgument>hasProperty("propertyName", desiredValue)));
import org.mockito.mockito
导入org.hamcrest.Matchers
...
Mockito.verify(mockedObject).someMethodOnMockedObject(MockitoHamcrest.argit)(
hasProperty(“propertyName”,desiredValue));

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

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

的参数,这是基于注释()的答案。我认为它有一些优点:

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

@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"));
    }
}
@RunWith(MockitoJUnitRunner.class)
公共类测试{
@俘虏
私家侦探;
//...
@试验
public void shouldTestArgsVals(){
//...
验证(mockedObject).someMethodOnMockedObject(captor.capture());
资产(captor.getValue().getXXX())为(“预期”);
}
}

如果您使用的是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);
    }
}
import java.util.Optional;
导入java.util.function.Predicate;
导入org.hamcrest.BaseMatcher;
导入org.hamcrest.Description;
公共类LambdaMatcher扩展了BaseMatcher
{
私有最终谓词匹配器;
私人最终可选描述;
公共LambdaMatcher(谓词匹配器)
{
这个(匹配器,空);
}
公共LambdaMatcher(谓词匹配器,字符串描述)
{
this.matcher=matcher;
this.description=可选的空值(description);
}
@抑制警告(“未选中”)
@凌驾
公共布尔匹配(对象参数)
{
返回matcher.test((T)参数);
}
@凌驾
公共无效说明(说明)
{
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()))));
}
@测试
公共无效可查找员工()
{
员工=新员工(“约翰”);
公司、增聘员工(员工);
验证(mockedDal).registerEmployee(argit)(新LambdaMatcher(e->e.getName())
.equals(employee.getName());
}

更多信息:

您可以参考以下内容:

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

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

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

当您使用其他未实现.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());

在我的案例中,上述解决方案并没有真正起作用。我不能使用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)));

来自
com.nhaarman.mockito_kotlin

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

另一个简单的方法是:

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;
            }
        }));
import org.mockito.BDDMockito;
导入静态org.mockito.Matchers.argThat;
导入org.mockito.ArgumentMatcher;
BDDMockito.verify(mockedObject)
.someMethodOnMockedObject(argThat(新参数匹配器(){
@凌驾
公共布尔匹配(对象参数){
最后一个TypeOfMethodArg castedArg=(TypeOfMethodArg)参数;
//进行验证并返回一个布尔值,以说明是否匹配
布尔值=真;
归来行军;
}
}));

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

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

如果您的方法有多个参数,则必须对所有其他参数使用匹配器。如果有多个参数呢?如何指定您感兴趣的确切参数?@IgorGanapolsky为您需要执行的doSomething假设第二个字符串参数:verify(mock).doSomething(argument.capture(),anyString());所有参数都需要使用匹配器,这完全符合标准的“全部”或“无”匹配器使用规范。这仅适用于参数中的单个参数。您可以对多个参数使用一个captor。如果捕获多个参数,可以使用
captor.getAllValues()
列出所有结果。answer中使用的方法
captor.getValue()
提供了最后一个结果。旁注:在编写sam时,确保
Matchers
包是正确的
verify(mock).execute(argThat {
    this.param = expected
})
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;
            }
        }));