2017-04-07 2 views
2

tl; dr: Diese Tests werden nicht kompiliert, da die Typparameter nicht übereinstimmen. Welche Änderungen sollte ich vornehmen, damit sie kompilieren und korrekt ausführen?Mockito, argThat und hasEntry

https://github.com/wesleym/matchertest

Ich habe einige Nicht-Test-Code, der in einen Dienst aufruft. Es ruft die activate-Methode des Dienstes mit einem map-Parameter auf.

public class Foo { 
    private final Service service; 

    public Foo(Service service) { 
    this.service = service; 
    } 

    public void bar() { 
    Map<String, ?> params = getParams(); 
    service.activate(params); 
    } 

    private Map<String, ?> getParams() { 
    // something interesting goes here 
    } 
} 

Einige Code, den ich zu Test bin versucht hat eine Abhängigkeit von einem Dienst wie diese:

public interface Service { 
    public void activate(Map<String, ?> params); 
} 

Ich möchte diesen Code testen, indem Sie den Dienst mit Mockito und Verifizieren verspotten, die aktivieren wurde mit einer vernünftigen Karte aufgerufen. Der folgende Code funktioniert:

@Test 
public void testExactMap() { 
    Service mockService = mock(Service.class); 
    Foo foo = new Foo(mockService); 

    foo.bar(); 

    Map<String, String> expectedParams = new HashMap<>(); 
    expectedParams.put("paramName", "paramValue"); 
    verify(service).activate(expectedParams); 
} 

Allerdings möchte ich nur testen, dass die Karte einen bestimmten Eintrag enthält. Die hamcrest hasEntry matcher scheint perfekt für diesen Anwendungsfall:

@Test 
public void testHasEntry() { 
    Service mockService = mock(Service.class); 
    Foo foo = new Foo(mockService); 

    foo.bar(); 

    verify(mockService).activate(argThat(hasEntry("paramName", "paramValue"))); 
} 

Wenn ich das versuche, erhalte ich folgende Fehlermeldung in IntelliJ IDEA:

Error:(31, 45) java: incompatible types: inference variable T has incompatible bounds 
    equality constraints: java.util.Map<? extends java.lang.String,? extends java.lang.String> 
    upper bounds: java.util.Map<java.lang.String,?>,java.lang.Object 

Das Problem hier ist, dass ich eine Mockito Matcher von Map<String, ?> brauchen , aber hasEntry gibt mir einen Matcher von Map<? extends String, ? extends String>. Selbst mit expliziten Typparametern kann ich nicht herausfinden, was zu tun ist, um den "? Extends" -Teil des Typparameters abzustimmen. Was muss ich tun, um diesen Fehler zu beheben? Gibt es einen bestimmten Cast- oder expliziten Typparameter, den ich verwenden sollte?

Ich verstehe, dass ich ArgumentCaptor dafür verwenden kann. Ist das wirklich der einzige Weg, dies zu tun? Ist das überhaupt möglich mit Hamcrest Matcher?

Antwort

3

Der Rückgabetyp argThat wird aus irgendeinem Grund nicht abgeleitet. Versuchen Sie unten, wie gezeigt explizit Casting:

Mockito.verify(foo).bar((Map<String, String>) argThat(Matchers.hasEntry("paramName", "paramValue"))); 

Die testHasEntryCast() kann festgelegt werden, wie unten gezeigt. Beachten Sie, dass (Map<String, ?>) gegossen ist argThat Rückgabetyp:

@Test 
public void testHasEntryCast() { 
    Service mockService = mock(Service.class); 
    Foo foo = new Foo(mockService); 

    foo.bar(); 

    verify(mockService).activate((Map<String, ?>) argThat(hasEntry("paramName", "paramValue"))); 
} 
+0

Zuerst hatte ich die falsche Code-Schnipsel auf. Es tut uns leid! Jetzt korrigiert. Zweitens funktioniert das nicht. Service.activate erwartet 'Map ', aber der Platzhalter ist in der Besetzung nicht erlaubt. Das Ersetzen von '?' Durch 'Object' funktioniert auch nicht. – Wesley

+0

Können Sie Testcode einschließlich Imports teilen? – VinPro

+0

Ich habe einen Link zu einem Beispielprojekt zu der Frage hinzugefügt. – Wesley