J'ai un appel de méthode dont je veux me moquer avec mockito. Pour commencer, j'ai créé et injecté une instance d'un objet sur lequel la méthode sera appelée. Mon but est de vérifier l'un des objets dans l'appel de méthode.
Existe-t-il un moyen que mockito vous permet d'affirmer ou de vérifier l'objet et ses attributs lorsque la méthode fictive est appelée?
exemple
Mockito.verify(mockedObject)
.someMethodOnMockedObject(
Mockito.<SomeObjectAsArgument>anyObject())
Au lieu de faire anyObject()
je veux vérifier que l'objet argument contient des champs particuliers
Mockito.verify(mockedObject)
.someMethodOnMockedObject(
Mockito.<SomeObjectAsArgument>**compareWithThisObject()**)
Une nouvelle fonctionnalité ajoutée à Mockito rend cela encore plus facile,
ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
verify(mock).doSomething(argument.capture());
assertEquals("John", argument.getValue().getName());
Jetez un coup d'œil à Mockito documentation
Dans le cas où il y a plus d'un paramètre et que vous souhaitez capturer un seul paramètre, utilisez d'autres ArgumentMatchers pour envelopper le reste des arguments:
verify(mock).doSomething(eq(someValue), eq(someOtherValue), argument.capture());
assertEquals("John", argument.getValue().getName());
Je pense que le moyen le plus simple de vérifier un objet argument est d'utiliser la méthode refEq
:
Mockito.verify(mockedObject).someMethodOnMockedObject(Matchers.refEq(objectToCompareWith));
Il peut être utilisé même si l'objet n'implémente pas equals()
, car la réflexion est utilisée. Si vous ne voulez pas comparer certains champs, ajoutez simplement leurs noms en tant qu'arguments pour refEq
.
Une autre possibilité, si vous ne souhaitez pas utiliser ArgumentCaptor
(par exemple, parce que vous utilisez également le stubbing), consiste à utiliser Hamcrest Matchers en combinaison avec Mockito.
import org.mockito.Mockito
import org.hamcrest.Matchers
...
Mockito.verify(mockedObject).someMethodOnMockedObject(Mockito.argThat(
Matchers.<SomeObjectAsArgument>hasProperty("propertyName", desiredValue)));
Ceci est une réponse basée sur réponse de iraSenthil mais avec une annotation ( Captor ). À mon avis, il présente certains avantages:
Exemple:
@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"));
}
}
Si vous utilisez Java 8, vous pouvez utiliser des expressions Lambda pour faire correspondre les expressions.
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);
}
}
Exemple d'appel
@Test
public void canFindEmployee()
{
Employee employee = new Employee("John");
company.addEmployee(employee);
verify(mockedDal).registerEmployee(argThat(new LambdaMatcher<>(e -> e.getName()
.equals(employee.getName()))));
}
Plus d'infos: http://source.coveo.com/2014/10/01/Java8-mockito/
Les solutions ci-dessus ne fonctionnaient pas vraiment dans mon cas. Je ne pouvais pas utiliser ArgumentCaptor car la méthode était appelée à plusieurs reprises et je devais valider chacune d'entre elles. Un simple Matcher avec "argThat" a fait l'affaire facilement.
Custom 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);
}
}
Test Runner
// 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)));
Et très belle et propre solution en koltin de com.nhaarman.mockito_kotlin
verify(mock).execute(argThat {
this.param = expected
})
Un autre moyen facile de le faire:
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;
}
}));
Vous pouvez vous référer aux éléments suivants:
Mockito.verify(mockedObject).someMethodOnMockedObject(eq(desiredObject))
Cela vérifiera si la méthode de mockedObject est appelée avec désiréObject en tant que paramètre.
Le javadoc de refEq a indiqué que le contrôle d'égalité est superficiel! Vous pouvez trouver plus de détails sur le lien ci-dessous:
Le problème "faible égalité" ne peut pas être contrôlé lorsque vous utilisez d'autres classes qui n'implémentent pas la méthode .equals (). La classe "DefaultMongoTypeMapper" est un exemple où la méthode .equals () n'est pas implémentée.
org.springframework.beans.factory.support offre une méthode qui peut générer une définition de bean au lieu de créer une instance de l'objet et qui peut être utilisée pour supprimer l'élimination de l'échec de la comparaison.
genericBeanDefinition(DefaultMongoTypeMapper.class)
.setScope(SCOPE_SINGLETON)
.setAutowireMode(AUTOWIRE_CONSTRUCTOR)
.setLazyInit(false)
.addConstructorArgValue(null)
.getBeanDefinition()
** "La définition du bean est seulement une description du bean, pas un bean lui-même. Les descriptions du bean implémentent correctement equals () et hashCode (). Par conséquent, plutôt que de créer un nouveau DefaultMongoTypeMapper (), nous fournissons une définition devrait en créer un "
Dans votre exemple, vous pouvez faire quelque chose comme ça
Mockito.verify(mockedObject)
.doSoething(genericBeanDefinition(YourClass.class).setA("a")
.getBeanDefinition());