web-dev-qa-db-fra.com

Vérifier la valeur de l'attribut d'objet avec mockito

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()**)
236
Priyank

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());
487
iraSenthil

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.

53
John29

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)));
44
charleyc

Ceci est une réponse basée sur réponse de iraSenthil mais avec une annotation ( Captor ). À mon avis, il présente certains avantages:

  • c'est plus court
  • c'est plus facile à lire
  • il peut gérer les génériques sans avertissements

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"));
    }
}
15
Walery Strauch

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/

8
GuiSim

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)));
4
whizzle

Et très belle et propre solution en koltin de com.nhaarman.mockito_kotlin

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

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

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.

1
zaid bepari

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:

[ https://static.javadoc.io/org.mockito/mockito-core/2.2.29/org/mockito/ArgumentMatchers.html#refEq (T,% 20Java.lang.String ...)] [1]

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());
0
Saif Masadeh