2017-10-04 5 views
3

ich den folgenden Code haben initialisiert werden:Mockito Spion ist fehlgeschlagen, da Klassenmitglied kann nicht

public class MyClass() { 
    private MyObject myObject = getMyObject(); 
    public MyObject getMyObject() { 
     if (myObject == null) { 
      myObject = MyStaticClass.createMyObject(); 
     } 
     return myObject; 
    } 
    // heaps more methods 
} 

public class MyTest() { 
    private MyClass spyMyClass = spy(new MyClass()); 
    public MyTest() { 
     doReturn(null).when(spyMyClass).getMyObject(); 
    } 
    @Test 
    public void someTest() { 
     ClassUnderTest c = new ClassUnderTest(); 
     assertTrue(c.someMethod(spyMyClass)); 
    } 
} 

Der Test mit einem Fehler gescheitert Could not initialise class MyStaticClass. Der Grund dafür ist, dass diese statische Klasse viele weitere Klassenobjekte initialisiert, die während des Tests nicht verfügbar sind (z. B. Datenbank), und es ist mir egal, wie Sie sehen können. Ich bin in Ordnung, wenn die Methode getMyObject() aufgerufen wird.

Aber das scheiterte Absicht als auch, weil vor der doReturn(null) Linie erreicht ist, hat der Test bereits in der spy(new MyClass()) Linie gescheitert, in dem es getMyObject() das private Mitglied myObject zu initialisieren nennt.

Eine Abhilfe auf die oben beschriebene Situation ist mock(MyClass.class) statt spy(new MyClass()), zu verwenden, so dass der private Mitglied myObject ist nicht initialisiert werden und somit nicht die reale getMyObject() Methode aufrufen.

Aber diese Problemumgehung erzeugt einen weiteren Kopfschmerz für mich, denn das bedeutet, dass ich einige Konfiguration vornehmen muss (sogar nur doCallRealMethod()) für diese Haufen mehr Methoden innerhalb MyClass.

Frage: Gibt es eine andere Lösung, die ich immer noch Spion auf einer Instanz von MyClass verwenden kann, so dass ich diese Heaps mehr Methoden innerhalb dieser Klasse konfigurieren kann, aber ich kann um den Could not initialise class MyStaticClass Fehler umgehen?

P.S. Ich kann nicht einfach Power Mock verwenden, um MyStaticClass zu verspotten, weil ich bereits einen anderen Test-Runner für MyTest verwende. Es sei denn, Ihre Antwort kann zeigen, wie einfach es ist, zwei Testläufer gleichzeitig zu fahren, ohne einen neuen Hybrid-Testläufer zu implementieren, der beides kombiniert.


Dank Adam, jetzt habe ich ein gutes Arbeits Code haben:

public class MyTest() { 
    private MyClass spyMyClass = spy(new MyClass() { 
     @Override 
     public MyObject getMyObject() { 
      return null; 
     } 
    }); 
    @Test 
    public void someTest() { 
     ClassUnderTest c = new ClassUnderTest(); 
     assertTrue(c.someMethod(spyMyClass)); 
    } 
} 

Antwort

2

eine Unterklasse von MyClass erstellen und es in private MyClass spyMyClass = spy(new TestMyClass()); verwenden:

class TestMyClass extends MyClass { 

    @Override // fortunately, the original method called in constructor can be overridden (what could be considered bad) 
    public MyObject getMyObject() { 
    // something that does not fail the constructor 
    } 

} 

Im Allgemeinen ist dies ein Mögliche Ursache für Probleme, da Sie eine nicht-private, nicht-finale Methode in Ihrem Konstruktor aufrufen. Für den Testfall könnte es akzeptabel sein.

Ein bisschen weg, ich denke, es wäre klug, einen Blick auf die Verantwortlichkeiten dieses MyClass Objekts zu werfen. Ist es nicht zu viel, deshalb ist es schwer zu testen und zu interagieren? Dies führt oft zu "schwer zu verspotten" -Syndrom.

+0

Danke, es sieht gut aus. Ist es Standard beim Komponententest? 'MyClass' ist eine Util-Klasse. Nicht viel tun, aber hat viele Varianten der gleichen Funktionen (z. B. Varianten von 1 oder 2 oder 3 Parameter), so dass ich nur widerwillig bin, alle von ihnen zu verspotten. – user1589188

+1

Man könnte argumentieren, dass Multi-Parameter-Schnittstelle Bloat das Problem erhöhen kann. Aber ohne die Quelle zu sehen, ist es schwer, explizit zu antworten. Ich würde die andere Frage stellen - macht 'MyClass' viele Dinge: z.B. geben Sie Datenbankkonfiguration + Serverkonfiguration geben + Anwendungskonfiguration geben? Wenn dies der Fall ist, könnte es in drei separate Einheiten aufgeteilt werden, die nur über Schnittstellen sichtbar sind. Dann sollten sie leichter zu verspotten sein. –

Verwandte Themen