2015-08-13 16 views
12

dire che sono beffardo questa classe FooMockito può verificare che un argomento abbia determinate proprietà/campi?

class Foo { 
    public void doThing(Bar bar) { 
    // ... 
    } 
} 

e questo è Bar

class Bar { 
    private int i; 
    public int getI() { return i; } 
    public void setI(int i) { this.i = i; } 
} 

So che posso usare verificare le funzionalità di Mockito per vedere se Foo#doThing(Bar) è stato chiamato sul finto con una specifica istanza di Bar o qualsiasi Bar con Mockito.any(Bar.class), ma c'è un modo per assicurarsi che sia stato chiamato da qualsiasi Bar ma con un valore specifico per i o Bar#getI()?

Quello che so è possibile:

Foo mockedFoo = mock(Foo.class); 
Bar someBar = mock(Bar.class); 
... 
verify(mockedFoo).doThing(someBar); 
verify(mockedFoo).doThing(any(Bar.class); 

Quello che voglio sapere è se c'è un modo per verificare che un Bar con cose particolari vere su di esso è stato passato come argomento.

risposta

10

In Mockito 2.1.0 e versioni successive con Java 8 è possibile passare il lambda a argThat out of the box in modo tale che non sia necessario un parametro matcher personalizzato. Per l'esempio nel PO sarebbe:

verify(mockedFoo).doThing(argThat(aBar -> aBar.getI() == 5)); 

Questo perché di Mockito 2.1.0, ArgumentMatcher è un'interfaccia funzionale.

11

Se si utilizza Mockito 2.1.0 o versione successiva e Java 8 o versione successiva, vedere la risposta this invece, è molto più semplice ora.


Ho trovato la risposta mentre scrivevo la domanda.

Sì, è possibile. Invece di utilizzare any(Bar.class) è necessario implementare la propria istanza di ArgumentMatcher<T> e utilizzare Mockito#argThat(Matcher), per esempio, diciamo che vogliamo controllare che i è 5 ...

// in the test (could also be outside) 

private static final class BarIs5 extends ArgumentMatcher<Bar> { 

    @Override 
    public boolean matches(Object argument) { 
    return ((Bar) argument).getI() == 5; 
    } 
} 

Poi verificare in questo modo: verify(mockedFoo).doThing(argThat(new BarIs5()));


Rilanciare una tacca aggiungendo i parametri del costruttore!

private static final class BarIsWhat extends ArgumentMatcher<Bar> { 

    private final int i; 

    public BarIsWhat(int i) { 
    this.i = i 
    } 

    @Override 
    public boolean matches(Object argument) { 
    return ((Bar) argument).getI() == i; 
    } 
} 

Poi verificare in questo modo: verify(mockedFoo).doThing(argThat(new BarIsWhat(5)));


Aggiornamento: Questo spuntato nella mia coda a causa di un badge e ho visto un po 'di margine di miglioramento.

Ho provato questo e funziona. Puoi usare un'espressione lambda che è molto più pulita (se non ti dispiace almeno gli avvertimenti cast non selezionati).

L'unico problema è che argThat accetta un Hamcrest Matcher che è non un @FunctionalInterface. Fortunatamente, lo ArgumentMatcher di Mockito è una classe astratta che lo estende e ha un solo metodo astratto.

Nella prova (o una certa posizione comune) effettuare un metodo come di seguito

private static <T> ArgumentMatcher<T> matches(Predicate<T> predicate) { 
    return new ArgumentMatcher<T>() { 

    @SuppressWarnings("unchecked") 
    @Override 
    public boolean matches(Object argument) { 
     return predicate.test((T) argument); 
    } 
    }; 
} 

Ora, nel test che si può fare questo per usare un'espressione lambda:

verify(mockedFoo).doThing(argThat(matches((Bar arg) -> arg.getI() == 5))); 
Problemi correlati