2017-02-06 4 views
2

Ich versuche, eine DateFormat-Klasse zu verspotten, da sie im Rahmen meines Komponententests keinen Zweck hat. Ich verwende die Bibliothek org.mockito.Mockito.Verspotten einer DateFormat-Klasse im Junit-Test

Code Folgende:

import static org.mockito.Mockito.when; 
import static org.mockito.Mockito.any; 
import org.mockito.Mock; 
import org.mockito.MockitoAnnotations; 

import org.junit.Before; 

public class someTest { 

    @Mock 
    DateFormat formatter; 

    @Before 
    public void before() { 
     MockitoAnnotations.initMocks(this); 
     when(formatter.format(any(Date.class))).thenReturn("2017-02-06"); 
    } 
} 

Gibt folgende Fehler:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers! 3 matchers expected, 1 recorded:

-> at someTest.before(someTest.java:33)

This exception may occur if matchers are combined with raw values: //incorrect: someMethod(anyObject(), "raw String"); When using matchers, all arguments have to be provided by matchers. For example: //correct: someMethod(anyObject(), eq("String by matcher"));

For more info see javadoc for Matchers class.

at java.text.DateFormat.format(Unknown Source)
at someTest.before(someTest.java:33)

Wie verspotten wir die Dateformat-Klasse in einem richtigen Weg?

+0

Wäre es nicht genauso einfach, eine echte Instanz zu erstellen? 'formatter = new SimpleDateFormat ('' 2017-02-06 '');' –

+0

@AndyTurner Was ist der Vorteil einer realen Instanz im Vergleich zu einem Mocked-Objekt? – henrik

+1

Ich werde diese Frage an Sie wenden: Was glauben Sie, gewinnen Sie, indem Sie dieses Objekt verspotten, anstatt eine echte Instanz zu benutzen? –

Antwort

4

Das Problem ist bei der Implementierung von format(Date date)

public final String format(Date date) { 
    return format(date, new StringBuffer(), 
        DontCareFieldPosition.INSTANCE).toString(); 
} 

Wie Sie sehen können, ist es endgültig. Mockito kann keine finalen Methoden vortäuschen. Stattdessen wird es die echte Methode nennen. Als Abhilfe können Sie Methode format(date, new StringBuffer(), DontCareFieldPosition.INSTANCE)

when(formatter.format(any(Date.class), any(StringBuffer.class), 
         any(FieldPosition.class))) 
    .thenReturn(new StringBuffer("2017-02-06")); 

So spotten, wenn Methode format(date) Ihre verspottet Methode das Ergebnis sein wird, rufen wird, wie Sie erwartet.

+0

Vielen Dank, dass Sie auf die Ursache des Fehlers hingewiesen haben. Die vom Framework zur Verfügung gestellte Fehlermeldung war ein wenig verwirrend. Ihre zur Verfügung gestellte Problemumgehung ist in Ordnung für mich! – henrik

+1

Das kleine Detail, das hier fehlt (oder vielleicht nicht klar genug ist) ist, dass der 'when' Aufruf die reelle Methode aufruft, die die Delegate-Methode aufruft - also die erste, die mockito über den' when' Aufruf weiß Wenn die Delegate-Methode aufgerufen wird, müssen Sie den Mock-Aufruf für * diese * Methode konfigurieren. Dies bedeutet, dass Ihr Testcode von Implementierungsdetails von 'TextFormat' abhängig ist - dies macht den Testcode spröde, als Folge des [Fragile Base Class Problems] (https://en.m.wikipedia.org/wiki/ Fragile_base_class). –

+0

@AndyTurner Du meinst DateFormat, nicht TextFormat, oder? Sonst bin ich verwirrt :) Ja, Sie haben Recht, Änderungen im Mockit Framework können dazu führen, dass der Test aufhört zu funktionieren, aber das ist Flossen mit mir. Aktualisierungstests werden im Vergleich zum Produktionscode leicht verwaltet. Guter Punkt, obwohl! – henrik

2

Wie von Serghey Bishyr hingewiesen, versuchen Sie, eine final method zu verspotten, die in Mockito nicht gemacht werden kann.

Wenn Ihr spöttisches Framework Ihnen nicht erlaubt, etwas zu tun (wie eine finale Methode zu verspotten), müssen Sie entweder ein alternatives Framework (wie Powermock) finden oder es auf andere Weise umgehen.

Vom Wikipedia article about mocks:

In a unit test, mock objects can simulate the behavior of complex, real objects and are therefore useful when a real object is impractical or impossible to incorporate into a unit test. If an object has any of the following characteristics, it may be useful to use a mock object in its place:

  • the object supplies non-deterministic results (e.g. the current time or the current temperature);
  • it has states that are difficult to create or reproduce (e.g. a network error);
  • it is slow (e.g. a complete database, which would have to be initialized before the test);
  • it does not yet exist or may change behavior;
  • it would have to include information and methods exclusively for testing purposes (and not for its actual task).

Keine der oben genannten Punkte gelten für Ihren Code, so gibt es keine Notwendigkeit, ein Mock zu verwenden. Und es ist nicht "unpraktisch oder unmöglich", eine echte Implementierung von DateFormat zu verwenden.

Statt ein verspottete DateFormat zu versorgen, liefern ein SimpleDateFormat:

formatter = new SimpleDateFormat("'2017-02-06'"); 

Dies wird immer 2017-02-06 Rückkehr für jede Eingabe, wie scheinbar aus dem Code in der Frage erwünscht, da ' s den Text zwischen ihnen bewirken, wörtlich genommen werden.

+0

Wir geben Ihnen +1 für einen Workaround! – henrik

0

über die richtigen Antworten, ein wichtiger Hinweis:

when(formatter.format(any(Date.class)) 

Wenn die Methode nicht endgültig sein würde, könnte man mit

when(formatter.format(any()) 

Mockito ist klug genug, um zu verstehen, gehen Sie einfach, was kommt und Was passiert (zumindest bei Verwendung von Java8)

Verwandte Themen