2009-07-17 16 views
181

Ich habe einen Methodenaufruf, den ich mit Mockito spotten möchte. Zu Beginn habe ich eine Instanz eines Objekts erstellt und injiziert, auf der die Methode aufgerufen wird. Mein Ziel ist es, eines der Objekte im Methodenaufruf zu verifizieren.Überprüfen Objekt Objekt Wert mit Mockito

Gibt es eine Möglichkeit, mit der Mockito das Objekt und seine Attribute bestätigen oder überprüfen kann, wenn die Mock-Methode aufgerufen wird?

Beispiel

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

Statt anyObject() zu tun, ich will dieses Argument Objekt überprüfen, enthält einige bestimmte Felder

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

Antwort

383

Neue Funktion hinzugefügt, um Mockito dies noch einfacher macht,

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

Werfen Sie einen Blick auf Mockito documentation

+0

Wenn Ihre Methode mehr als ein Argument hat, müssen Sie Matchers auch für alle anderen Argumente verwenden. https://akcasoy.wordpress.com/tag/argumentcaptor/ – robsonrosa

+1

Was ist, wenn es mehrere Argumente gibt? Wie geben Sie genau den an, an dem Sie interessiert sind? –

+2

@IgorGanapolsky Angenommen, Sie benötigen einen zweiten String-Parameter für doSomething: verify (mock) .doSomething (argument.capture(), anyString()); – GreenTurtle

39

Eine weitere Möglichkeit, wenn Sie nicht ArgumentCaptor verwenden wollen (zum Beispiel, weil Sie Verwenden Sie auch Stubbing, verwenden Sie Hamcrest Matchers in Kombination mit Mockito.

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

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

Hinweis: Stellen Sie sicher, dass das Paket 'Matchers' korrekt ist, da beim Schreiben der gleichen Codezeile mit der Klasse' org.mockito.Matchers' eine irreführende Ausnahme ausgegeben wird, die besagt, dass der Parameter der Funktion mock nicht übereinstimmt. – buer

34

Ich denke, der einfachste Weg, ein Argument Objekt für die Überprüfung ist die refEq Methode zu verwenden:

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

Es auch verwendet werden kann, wenn das Objekt nicht equals() nicht implementiert, weil Reflexion verwendet wird. Wenn Sie einige Felder nicht vergleichen möchten, fügen Sie einfach ihre Namen als Argumente für refEq hinzu.

+0

Dies testet auf Referenzgleichheit (das gleiche Objekt ist nicht gleich). –

+2

@Adam Arold Nein, "ref" bedeutet nicht Referenz, es bedeutet Reflexion. Siehe den Quellcode in 'org.mockito.Matchers'. – John29

+0

Es ändert nicht die Tatsache, dass es nicht funktioniert. Ich versuchte es. –

9

Dies ist die Antwort basierend auf answer from iraSenthil aber mit Anmerkung (Captor). Meiner Meinung nach hat es einige Vorteile:

  • es ist kürzer
  • es einfacher ist,
  • es lesen Generika ohne Warnungen umgehen kann

Beispiel:

@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

Der "Captor" Link ist gebrochen – Thermech

+1

@Thermech Thx, ist jetzt behoben :) –

+0

Dies wird nur für ein einzelnes Argument in Params funktionieren. –

4

Wenn Sie‘ Wenn Sie Java 8 verwenden, können Sie Lambda-Ausdrücke zum Vergleich verwenden.

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

Beispielaufruf

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

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

Weitere Informationen: http://source.coveo.com/2014/10/01/java8-mockito/

0

Sie können das finden folgende:

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

Dies wird prüfen, ob Verfahren von mockedObject mit desiredObject als Parameter aufgerufen wird .

0

Das Javadoc für RefEq erwähnt, dass die Überprüfung der Gleichheit flach ist! Sie können weitere Informationen unter dem folgenden Link finden:

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

„flache Gleichheit“ -Ausgabe nicht kontrolliert werden kann, wenn Sie andere Klassen verwenden, die .equals() -Methode nicht umsetzen „DefaultMongoTypeMapper“ Klasse ein ist Beispiel, wo. equals() -Methode nicht implementiert ist.

org.springframework.beans.factory.support bietet eine Methode, die eine Bean-Definition generieren kann, anstatt eine Instanz des Objekts zu erstellen, und sie kann verwendet werden, um den Vergleich fehlzuschlagen.

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

** "Die Bohne Definition ist nur eine Beschreibung der Bohne, nicht eine Bohne selbst. die Bohne Beschreibungen richtig equals() implementieren und hashCode(), so, anstatt eine neue DefaultMongoTypeMapper zu schaffen() wir bieten eine Definition, die Feder sagt, wie es sollte ein“

in Ihrem Beispiel erstellen, können Sie tun somethong wie diese

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

Die oben genannten Lösungen nicht wirklich in meinem Fall nicht funktioniert. Ich konnte ArgumentCaptor nicht verwenden, da die Methode mehrmals aufgerufen wurde und ich jedes einzelne validieren musste. Ein einfacher Matcher mit "argThat" hat den Trick leicht gemacht.

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