2009-07-17 19 views
181

Ho una chiamata al metodo che voglio prendere in giro con mockito. Per cominciare ho creato e iniettato un'istanza di un oggetto su cui verrà chiamato il metodo. Il mio obiettivo è verificare uno degli oggetti nella chiamata al metodo.Verificare il valore di attributo dell'oggetto con mockito

C'è un modo in cui mockito consente di affermare o verificare l'oggetto e gli attributi quando viene chiamato il metodo di simulazione?

esempio

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

Invece di fare anyObject() voglio controllare l'oggetto argomento contiene alcuni campi particolari

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

risposta

383

nuova funzionalità aggiunta a Mockito rende ancora più facile,

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

Date un'occhiata a Mockito documentation

+0

se il tuo metodo ha più di un argomento, devi usare anche i Corrispondenti per tutti gli altri argomenti. https://akcasoy.wordpress.com/tag/argumentcaptor/ – robsonrosa

+1

Cosa succede se ci sono più argomenti? Come specifichi esattamente quello che ti interessa? –

+2

@IgorGanapolsky Assumendo un secondo parametro String per doSomething che devi fare: verificare (mock) .doSomething (argument.capture(), anyString()); – GreenTurtle

39

più Una possibilità, se non si desidera utilizzare ArgumentCaptor (ad esempio, perché si stiamo usando anche lo stub), è usare Hamcrest Matchers in combinazione con Mockito.

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

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

Sidenote: assicurati che il pacchetto 'Matchers' sia corretto, poiché scrivere la stessa riga di codice con la classe' org.mockito.Matchers' genera un'eccezione fuorviante che afferma che il parametro della funzione fittizia semplicemente non corrisponde. – buer

34

ritengo il modo più semplice per la verifica di un argomento oggetto è quello di utilizzare il metodo refEq:

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

Può essere utilizzato anche se l'oggetto non implementa equals(), perché la riflessione viene utilizzato. Se non vuoi confrontare alcuni campi, aggiungi i loro nomi come argomenti per refEq.

+0

Questo test per l'uguaglianza di riferimento (stesso oggetto non 'equals'). –

+2

@Adam Arold No, "ref" non significa riferimento, significa riflessione. Vedi il codice sorgente in "org.mockito.Matchers'. – John29

+0

Non cambia il fatto che non funziona. L'ho provato. –

9

Questa è la risposta basata su answer from iraSenthil ma con annotazione (Captor). A mio parere ha alcuni vantaggi:

  • è più breve
  • è più facile da leggere
  • è in grado di gestire i farmaci generici senza avvisi

Esempio:

@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

Il collegamento "Captor" è rotto – Thermech

+1

@Thermech thx, è ora risolto :) –

+0

Questo funzionerà solo per un singolo argomento in params. –

4

Se si' utilizzando Java 8, è possibile utilizzare le espressioni Lambda per la corrispondenza.

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

chiamata Esempio

@Test 
public void canFindEmployee() 
{ 
    Employee employee = new Employee("John"); 
    company.addEmployee(employee); 

    verify(mockedDal).registerEmployee(argThat(new LambdaMatcher<>(e -> e.getName() 
                     .equals(employee.getName())))); 
} 

Maggiori informazioni: http://source.coveo.com/2014/10/01/java8-mockito/

0

è possibile consultare la seguente:

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

Questo sarà verificare se il metodo di mockedObject viene chiamato con desiredObject come parametro .

0

Il javadoc per refEq ha menzionato che il controllo di uguaglianza è superficiale! Potete trovare maggiori dettagli al link qui sotto:

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

"uguaglianza debole" questione non può essere controllato quando si utilizzano altri classi che non implementano .equals() metodo, "DefaultMongoTypeMapper" Classe è un esempio in cui il metodo .equals() non è implementato.

org.springframework.beans.factory.support offre un metodo che può generare una definizione di bean invece di creare un'istanza dell'oggetto e può essere utilizzata per eliminare il Confronto Failure.

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

** "La definizione di fagioli è solo una descrizione del chicco, non un fagiolo per sé. le descrizioni di fagioli implementano correttamente equals() e hashCode(), quindi piuttosto che creare un nuovo DefaultMongoTypeMapper() abbiamo fornire una definizione che racconta la primavera come si dovrebbe creare una"

nel tuo esempio, si può fare in questo modo somethong

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

Le soluzioni di cui sopra non ha funzionato davvero nel mio caso. Non ho potuto utilizzare ArgumentCaptor come il metodo è stato chiamato più volte e ho bisogno di convalidare ciascuno di essi. Un semplice Matcher con "argThat" ha fatto facilmente il trucco.

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