java mockito教學 - 使用mockito驗證對象屬性值




mockito教程 mockito中文 (9)

我有一個方法調用,我想用mockito來模擬。 首先我創建並註入了一個將調用該方法的對象的實例。 我的目標是驗證方法調用中的一個對象。

有沒有一種方法可以讓mockito斷言或驗證對象,並且在模擬方法被調用時它是屬性?

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

而不是做anyObject()我想檢查參數對象包含一些特定的字段

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

Answers

你可以參考以下內容:

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

這將驗證是否以desiredObject作為參數調用mockedObject的方法。



上述解決方案在我的情況下並不真正起作用。 我無法使用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)));

如果您不想使用ArgumentCaptor (例如,因為您也使用存根),另一種可能性是將Hamcrest Matchers與Mockito結合使用。

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

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

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的定義只是對bean的描述,而不是bean的本身,bean的描述正確地實現了equals()和hashCode(),所以不是創建一個新的DefaultMongoTypeMapper(),而是提供了一個定義,告訴Spring如何應該創建一個“

在你的例子中,你可以像這樣做一些事情

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

我認為驗證參數對象的最簡單方法是使用refEq方法:

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

即使對像沒有實現equals() ,也可以使用它,因為使用了反射。 如果您不想比較某些字段,只需將它們的名稱添加為refEq參數refEq


添加到Mockito中的新功能使這變得更加簡單,

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

看看Mockito documentation


這是根據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"));
    }
}

我認為你的問題是由於你的測試結構。 我發現很難將嘲諷與在測試類中實現接口的傳統方法混淆(正如您在此處所做的那樣)。

如果您將偵聽器實現為模擬,則可以驗證交互。

Listener listener = mock(Listener.class);
w.addListener(listener);
world.doAction(..);
verify(listener).doAction();

這應該讓你滿意,'世界'正在做正確的事情。





java mocking mockito