2009-07-17 93 views
181

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

有没有一种方法,mockito可以让你断言或验证对象,它的属性,当模拟方法被调用?

例如

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

而不是做anyObject()我要检查参数对象包含一些特定领域

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

回答

383

了新的功能,以使的Mockito这更容易,

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

看看documentation的Mockito

+0

如果你的方法有多个参数,你必须对所有其他参数使用Matchers。 https://akcasoy.wordpress.com/tag/argumentcaptor/ – robsonrosa 2015-08-05 17:07:08

+1

如果有多个参数会怎样?你如何指定你感兴趣的确切人物? – 2017-02-24 14:25:15

+2

@IgorGanapolsky假设你需要做doSomething的第二个String参数:verify(mock).doSomething(argument.capture(),anyString()); – GreenTurtle 2017-04-07 11:23:49

39

还有一个可能性,如果你不想使用ArgumentCaptor(例如,因为你'也使用stubbing),就是将Hamcrest Matchers与Mockito结合使用。

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

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

我想验证一个参数对象最简单的方法是使用refEq方法:

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

如果对象没有实现equals(),由于使用反射它甚至可以使用。如果您不想比较某些字段,只需将其名称添加为refEq的参数即可。

9

这是基于answer from 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")); 
    } 
} 
4

如果”重新使用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/

0

你可以参考以下几点:

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

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

0

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

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

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

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

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

**“的bean定义只是豆腐的描述,而不是豆本身。 豆说明正确实现equals()和hashCode(),这样,而不是创建一个新的DefaultMongoTypeMapper(),我们提供了一个定义,告诉春季应该如何创建一个”

在你的榜样,你可以做somethong这样

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

上述的方案并没有真正在我的情况下工作。我无法使用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)));