2009-07-17 15 views
181

J'ai un appel de méthode que je veux simuler 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.Vérifiez la valeur de l'attribut d'objet avec mockito

Existe-t-il un moyen pour mockito d'affirmer ou de vérifier l'objet et ses attributs lors de l'appel de la méthode fictive?

exemple

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

Au lieu de faire anyObject() je veux vérifier cet objet argument contient certains domaines particuliers

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

Répondre

383

Nouvelle fonctionnalité ajoutée à Mockito rend encore plus facile,

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

Jetez un oeil à Mockito documentation

+0

Si votre méthode comporte plusieurs arguments, vous devez également utiliser Matchers pour tous les autres arguments. https://akcasoy.wordpress.com/tag/argumentcaptor/ – robsonrosa

+1

Et s'il y a plusieurs arguments? Comment spécifiez-vous l'exact qui vous intéresse? –

+2

@IgorGanapolsky En supposant un second paramètre String pour quelque chose que vous devez faire: verify (mock) .doSomething (argument.capture(), anyString()); – GreenTurtle

39

Encore une possibilité, si vous ne voulez pas utiliser ArgumentCaptor (par exemple, parce que vous utilise é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))); 
+0

Sidenote: assurez-vous que le package 'Matchers' est correct, car l'écriture de la même ligne de code avec la classe' org.mockito.Matchers' renvoie une exception trompeuse indiquant que le paramètre de la fonction mock ne correspond tout simplement pas. – buer

34

Je pense que la meilleure façon 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 ne met pas en œuvre equals(), parce que la réflexion est utilisé. Si vous ne souhaitez pas comparer certains champs, ajoutez simplement leurs noms en tant qu'arguments pour refEq.

+0

Ceci teste l'égalité de référence (même objet pas 'equals'). –

+2

@Adam Arold Non, "ref" ne signifie pas référence, cela signifie réflexion. Voir le code source dans 'org.mockito.Matchers'. – John29

+0

Cela ne change rien au fait que ça ne marche pas. Je l'ai essayé. –

9

Cette réponse est basée sur answer from iraSenthil mais avec l'annotation (Captor). À mon avis, il a quelques avantages:

  • il est plus court
  • il est plus facile de lire
  • il peut gérer les médicaments génériques sans avertissement

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

Le lien "Captor" est rompu – Thermech

+1

@Thermech thx, est maintenant corrigé :) –

+0

Cela ne fonctionnera que pour un seul argument dans params. –

4

Si vous En utilisant Java 8, vous pouvez utiliser des expressions Lambda pour les faire correspondre.

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'info: http://source.coveo.com/2014/10/01/java8-mockito/

0

Vous pouvez consulter les éléments suivants:

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

Ceci permettra de vérifier si la méthode de mockedObject est appelée avec desiredObject en tant que paramètre . Le javadoc pour refEq a mentionné que le contrôle d'égalité est superficiel!

0

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]

question « égalité superficielle » ne peut pas être contrôlé lorsque vous utilisez d'autres classes qui ne mettent pas en œuvre 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 elle peut être utilisée pour se débarrasser de l'échec de comparaison.

genericBeanDefinition(DefaultMongoTypeMapper.class) 
         .setScope(SCOPE_SINGLETON) 
         .setAutowireMode(AUTOWIRE_CONSTRUCTOR) 
         .setLazyInit(false) 
         .addConstructorArgValue(null) 
         .getBeanDefinition() 

** "La définition de haricot est seulement une description de la fève, pas un grain lui-même. les descriptions de haricots mettent en œuvre correctement equals() et hashCode(), donc plutôt que de créer une nouvelle DefaultMongoTypeMapper() nous fournir une définition qui dit printemps comment il devrait créer un »

dans votre exemple, vous pouvez faire somethong comme ça

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

Les solutions ci-dessus ne fonctionne pas vraiment dans mon cas. Je ne pouvais pas utiliser ArgumentCaptor car la méthode était appelée plusieurs fois et j'avais besoin de valider chacun d'entre eux. Un simple Matcher avec "argThat" a fait le tour facilement.

sur mesure 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)));