2009-07-17 94 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)));