私はmockitoでモックしたいメソッド呼び出しを持っています。まず、メソッドが呼び出されるオブジェクトのインスタンスを作成して注入しました。私の目的は、メソッド呼び出しのオブジェクトの1つを検証することです。
Mockitoを使用して、mockメソッドが呼び出されたときにオブジェクトとその属性をアサートまたは検証できる方法はありますか?
例
Mockito.verify(mockedObject)
.someMethodOnMockedObject(
Mockito.<SomeObjectAsArgument>anyObject())
anyObject()
を行う代わりに、引数オブジェクトに特定のフィールドが含まれていることを確認したい
Mockito.verify(mockedObject)
.someMethodOnMockedObject(
Mockito.<SomeObjectAsArgument>**compareWithThisObject()**)
Mockitoに追加された新機能により、これがさらに簡単になり、
ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
verify(mock).doSomething(argument.capture());
assertEquals("John", argument.getValue().getName());
Mockitoをご覧ください ドキュメント
複数のパラメーターがあり、単一のパラメーターのみのキャプチャーが必要な場合、他のArgumentMatchersを使用して残りの引数をラップします。
verify(mock).doSomething(eq(someValue), eq(someOtherValue), argument.capture());
assertEquals("John", argument.getValue().getName());
引数オブジェクトを検証する最も簡単な方法は、refEq
メソッドを使用することだと思います。
Mockito.verify(mockedObject).someMethodOnMockedObject(Matchers.refEq(objectToCompareWith));
リフレクションが使用されるため、オブジェクトがequals()
を実装していない場合でも使用できます。一部のフィールドを比較したくない場合は、名前をrefEq
の引数として追加するだけです。
もう1つの可能性は、ArgumentCaptor
を使用したくない場合(たとえば、スタブも使用しているため)、Mockitoと組み合わせてHamcrest Matchersを使用することです。
import org.mockito.Mockito
import org.hamcrest.Matchers
...
Mockito.verify(mockedObject).someMethodOnMockedObject(Mockito.argThat(
Matchers.<SomeObjectAsArgument>hasProperty("propertyName", desiredValue)));
これは、 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"));
}
}
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()))));
}
私の場合、上記のソリューションは実際には機能しませんでした。メソッドが複数回呼び出され、それぞれを検証する必要があるため、ArgumentCaptorを使用できませんでした。 「argThat」を使用した簡単なMatcherで簡単にできました。
カスタムマッチャー
// 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
からのkoltinでのとても素敵できれいなソリューション
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;
}
}));
以下を参照できます。
Mockito.verify(mockedObject).someMethodOnMockedObject(eq(desiredObject))
これにより、mockedObjectのメソッドが、desiredObjectをパラメーターとして呼び出されるかどうかが検証されます。
RefEqのjavadocは、等価性チェックが浅いことを述べました!以下のリンクで詳細を確認できます。
.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()を作成するのではなく、作成する必要があります」
あなたの例では、このように何かをすることができます
Mockito.verify(mockedObject)
.doSoething(genericBeanDefinition(YourClass.class).setA("a")
.getBeanDefinition());