Wie testen anonyme Methoden mit Junit oder Mockito?

8

Ich habe eine einfache Klasse, aber mit einem anonymen Code-Block. Ich muss diese Klasse mit Tests abdecken.

%Vor%

Und testen:

%Vor%
  

Kommentarzeile funktioniert nicht. Protokoll: Gesucht, aber nicht aufgerufen:   dao.deleteAllByStatusAndDate (       ,       isA (java.util.Date));   - & gt; unter com.nxsystems.dw.publisher.handler.CleanerTaskTest.successfulScenario (CleanerTaskTest.java:52)   Eigentlich gab es keine Interaktionen mit diesem Mock.

     

um   com.nxsystems.dw.publisher.handler.CleanerTaskTest.successfulScenario (CleanerTaskTest.java:52)     bei sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Methode) um   sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:39)     beim   sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:25)     beim   org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall (FrameworkMethod.java:44)     beim   org.junit.internal.runners.model.ReflectiveCallable.run (ReflectiveCallable.java:15)     beim   org.junit.runners.model.FrameworkMethod.invokeExplosively (FrameworkMethod.java:41)     beim   org.junit.internal.runners.statements.InvokeMethod.evaluate (InvokeMethod.java:20)     beim   org.junit.internal.runners.statements.RunBefores.evaluate (RunBefores.java:28)     beim   org.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java:76)     beim   org.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java:50)     bei org.junit.runners.ParentRunner $ 3.run (ParentRunner.java:193) um   org.junit.runners.ParentRunner $ 1.schedule (ParentRunner.java:52) um   org.junit.runners.ParentRunner.runChildren (ParentRunner.java:191) um   org.junit.runners.ParentRunner.access $ 000 (ParentRunner.java:42) um   org.junit.runners.ParentRunner $ 2.evaluate (ParentRunner.java:184) um   org.junit.runners.ParentRunner.run (ParentRunner.java:236) um   org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run (JUnit45AndHigherRunnerImpl.java:37)     beim   org.mockito.runners.MockitoJUnitRunner.run (MockitoJUnitRunner.java:62)     an org.junit.runner.JUnitCore.run (JUnitCore.java:157) um   com.intellij.rt.execution.junit.JUnitStarter.main (JUnitStarter.java:62)

Auch wenn diese Tets gestartet werden, geht der Debugger nicht in den anonymen Block. Also, wie macht man Mockito in anonymen Block gehen?

    
Dmitrii Borovoi 15.08.2012, 00:08
quelle

2 Antworten

11

Warum es nicht funktioniert.

Nun, Ihr Problem hier ist, dass TransactionTemplate in Ihrem Test ein Mock ist. Als solches hat es die gleiche Schnittstelle wie TransactionTemplate, aber es weiß nicht, wie es sich verhält. Sie sind verantwortlich für die Umsetzung - das ist der springende Punkt von Mocks. Sie rufen template.execute() explizit in Ihrem Code auf und deshalb wird Ihre erste Überprüfung bestanden. Aber das execute() ist nicht das von Spring (genauer gesagt ist template in deinem Test keine Instanz von Spring's TransactionTemplate, es ist nur ein Mock davon) - es ist, na gut sagen Sie, es ist "leer", da es auf einem Schein aufgerufen wird und Sie haben dem Mock nicht gesagt, wie sich das Aufrufen von execute() verhalten soll.

Wie ich es beheben würde.

In solchen Fällen würde ich wirklich von solchen Unit-Tests abraten, weil Sie Implementierung hier testen. Was Sie testen sollten, zumindest für mich, ist die Funktionalität Bedeutung gegeben bestimmte Bedingungen, wenn etwas passiert dann Einige Ergebnisse sollten auftreten. Dies würde erfordern, dies zu einem Integrationstest zu ändern (unter Verwendung von beispielsweise DBUnit oder irgendetwas anderem) und festzustellen, ob Sie tatsächlich gelöscht haben, was Sie löschen sollten. Ich meine, was kümmert es dich wirklich - zu wissen, dass einige Methoden aufgerufen wurden oder dass etwas, auf das du gehofft hast, tatsächlich passiert ist?

Wie Sie können, aber ich sollte es nicht beheben.

Aber wenn Sie wirklich dieses anonyme Stück Code testen wollen, dann würde ich es einfach (die ganze anonyme Klasse) in eine separate Klasse extrahieren und einen Komponententest nur für diese neue Klasse schreiben und mehr Genau für die Methode doInTransaction() . In diesem Fall würden Sie es mit new erstellen, indem Sie einen Schein DataWarehouseMessageDao setzen und einfach Ihre verify() .

    
Mateusz Dymczyk 15.08.2012, 00:48
quelle
2

Sie sollten Ihren Code nicht ändern, es ist richtig. In Ihrem Komponententest sollten Sie anstelle von isA check ArgumentCaptor verwenden, um übergebene Parameter zu erfassen, diese Instanz als transactionCallback-Typ zu validieren und die Methode doInTransaction darauf aufzurufen. So könnten Sie überprüfen, ob dao mit dem erwarteten Parameter aufgerufen wurde (Sie könnten eq Matcher verwenden, um den genauen Wert zu überprüfen).

Es stimmt, dass du in diesem Test zwei Dinge gleichzeitig testest, aber es ist nur wegen deiner Implementierung und ich sage nicht, dass es falsch ist. Das Erstellen neuer Instanzen mit einer gewissen Geschäftslogik erhöht zwar die Kopplung in Ihrem Code, aber das bedeutet nicht, dass wir keine Sprachfähigkeiten dafür verwenden sollten.

    
Ruslan Dzhabbarov 20.08.2012 16:23
quelle

Tags und Links