mockitoでオブジェクトの属性値を確認する


264

mockitoでモックしたいメソッド呼び出しがあります。まず、メソッドが呼び出されるオブジェクトのインスタンスを作成して注入しました。私の目的は、メソッド呼び出しでオブジェクトの1つを検証することです。

mockitoを使用して、モックメソッドが呼び出されたときにオブジェクトとその属性をアサートまたは検証できる方法はありますか?

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

代わりにanyObject()、引数オブジェクトに特定のフィールドが含まれていることを確認したい

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

これらの場合にmockitoを使用する代わりに、mockedObjectのクラスを拡張し、someMethodOnMockedObjectをオーバーライドして後で比較するためにオブジェクトを保存するカスタムスタブを作成することを検討できます。
Gonen I

回答:


540

Mockitoに追加された新機能により、これがさらに簡単になり、

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

Mockitoのドキュメントをご覧ください


複数のパラメーターがあり、単一のパラメーターのみのキャプチャーが必要な場合は、他のArgumentMatcherを使用して残りの引数をラップします。

verify(mock).doSomething(eq(someValue), eq(someOtherValue), argument.capture());
assertEquals("John", argument.getValue().getName());

1
メソッドに複数の引数がある場合、他のすべての引数にもマッチャーを使用する必要があります。akcasoy.wordpress.com/tag/argumentcaptor
robsonrosa

1
複数の引数がある場合はどうなりますか?興味のある正確なものをどのように指定しますか?
IgorGanapolsky 2017

2
@IgorGanapolsky実行する必要があるdoSomethingの2番目の文字列パラメーターを想定:verify(mock).doSomething(argument.capture()、anyString());
GreenTurtle 2017

すべての引数にマッチャーを使用する必要性は、標準的なオール・オア・ノン・マッチャーの使用法仕様のみに基づいています。
Charney Kaye

54

引数オブジェクトを検証する最も簡単な方法は、refEqメソッドを使用することだと思います。

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

equals()リフレクションを使用しているため、オブジェクトがを実装していなくても使用できます。一部のフィールドを比較したくない場合は、フィールドの名前をの引数として追加しますrefEq


1
これは非常にエレガントな方法ですが、残念ながらorg.mockito.Matchersは非推奨になりました
ihebiheb

5
@ihebihebこれはArgumentMatchersに移動しました
Michael

48

ArgumentCaptor(たとえば、スタブを使用しているため)使用したくない場合のもう1つの可能性は、Hockrest MatcherをMockitoと組み合わせて使用​​することです。

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

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

2
補足:Matchersパッケージが正しいことを確認してください。org.mockito.Matchersクラスで同じコード行を書き込むと、モック関数のパラメーターが単に一致しないことを示す誤解を招く例外がスローされます。
18年

1
現代Mockitoのバージョンでは、それがあることに注意してくださいMockitoHamcrest.argThat()ではなくMockito.argThat()
ローマPuchkovskiy

17

これは、に基づいて回答ですiraSenthilからの回答が、注釈(とキャプター)。私の意見では、いくつかの利点があります:

  • 短いです
  • 読みやすい
  • 警告なしでジェネリックを処理できます

例:

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

これは、paramsの単一の引数に対してのみ機能します。
IgorGanapolsky 2017

1つのキャプターを複数の引数に使用できます。複数の引数を取得する場合は、を使用してすべての結果を一覧表示できますcaptor.getAllValues()captor.getValue()回答で使用される方法 は、最後の結果をもたらします。
Walery Strauch、2017

11

Java 8を使用している場合は、ラムダ式を使用して照合できます。

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/


5

上記の解決策は私の場合実際には機能しませんでした。メソッドが数回呼び出され、それぞれを検証する必要があるため、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)));

3

そして、コルティンの非常にきれいな溶液 com.nhaarman.mockito_kotlin

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

1

以下を参照できます。

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

これは、mockedObjectのメソッドがパラメーターとしてdesiredObjectを指定して呼び出されているかどうかを検証します。


1

これを行う別の簡単な方法:

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

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の定義は、Bean自体ではなく、Beanの説明にすぎません。Beanの説明は、equals()とhashCode()を適切に実装しているため、新しいDefaultMongoTypeMapper()を作成するのではなく、Springにその方法を伝える定義を提供します作成する必要があります」

あなたの例では、あなたはこのような何かをすることができます

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

0

新しいMatcher実装クラスを作成せず、ラムダ式を使用しない、シンプルなソリューション:

        verify(mockObject).someMockMethod(argThat((SomeArgument arg) -> arg.fieldToMatch.equals(expectedFieldValue));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.