2015-08-16 12 views
7

Angenommen, ich habe ein Programm, das wie folgt aussieht:Mit JMockit und Spring AOP zusammen

@Component 
public class MainAction { 
    public void doTheAction() { 
     System.out.println("Now doing the action"); 
    } 
} 

@Aspect 
@Component 
public class BeforeAspect { 
    @Autowired 
    private Logger logger; 

    @Before("execution(* thepackagename.MainAction.*(..))") 
    public void doBefore() { 
     logger.log("The @Before advice has run"); 
    } 
} 

@Component 
public class Logger { 
    public void log(String s) { 
     System.out.println(s); 
    } 
} 

Dies funktioniert gut, wenn ich es durch Eclipse-laufen (die wichtigste Methode esentially ruft mainAction.doTheAction() nach mainAction wird von Frühling erstellt) .

Jetzt möchte ich einen Test schreiben, der sicherstellt, dass die log Methode korrekt aufgerufen wird, wenn doTheAction aufgerufen wird. Wir verwenden JMockit für unsere Tests. (Dies ist ein sehr vereinfachter Fall eines Problems, mit dem ich tatsächlich konfrontiert bin; ein komplexerer Logger wird über einen AOP-Aspekt aufgerufen, und der falsche Wert von etwas wird protokolliert. Bevor ich an einem Fix arbeite, versuche ich einen zu schreiben Test, um sicherzustellen, der angemeldete Wert korrekt ist)

Dies ist, was mein (vereinfacht) Test zur Zeit wie folgt aussieht:.

@RunWith(JMockit.class) 
@ContextConfiguration(locations = {"classpath:Beans.xml"}) 
public class MainActionTest { 
    @Tested 
    private MainAction mainAction; 

    @Test 
    public void testThatLoggerIsCalled(@Injectable Logger logger) { 
     new Expectations() { { 
      logger.log(anyString); 
     } }; 
     mainAction.doTheAction(); 
    } 
} 

die @ContextConfiguration nutzlos sein kann. Früher hatte ich versucht @RunWith(SpringJunit4ClassRunner.class), weshalb @ContextConfiguration ist da, aber keiner der spöttischen Sachen wurde behandelt. Außerdem verwende ich @Tested und @Injectable anstelle von @Autowired und @Mocked, nach dem Vorschlag in this question; ohne diese blieb mainAction null. Jetzt läuft der Test und Now doing the action erscheint in der Ausgabe. Aber 10 erscheint nicht (und erscheint nicht einmal, wenn ich nicht die Logger) verspotten, und die Erwartung schlägt fehl.

Wie kann ich JMockit und AOP zusammen verwenden?

Bearbeiten: Wie gewünscht, habe ich etwas hinzugefügt, um die Classpath-Eigenschaft zu drucken. Hier ist es (mit unwichtigen Teilen einiger Pfadnamen entfernt):

Eclipse workspaces\springtest8\target\test-classes 
Eclipse workspaces\springtest8\target\classes 
C:\eclipse\plugins\org.junit_4.11.0.v201303080030\junit.jar 
C:\eclipse\plugins\org.hamcrest.core_1.3.0.v201303031735.jar 
.m2\repository\org\jmockit\jmockit\1.18\jmockit-1.18.jar 
.m2\repository\junit\junit\4.11\junit-4.11.jar 
.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar 
.m2\repository\org\springframework\spring-context\4.2.0.RELEASE\spring-context-4.2.0.RELEASE.jar 
.m2\repository\org\springframework\spring-aop\4.2.0.RELEASE\spring-aop-4.2.0.RELEASE.jar 
.m2\repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar 
.m2\repository\org\springframework\spring-beans\4.2.0.RELEASE\spring-beans-4.2.0.RELEASE.jar 
.m2\repository\org\springframework\spring-core\4.2.0.RELEASE\spring-core-4.2.0.RELEASE.jar 
.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar 
.m2\repository\org\springframework\spring-expression\4.2.0.RELEASE\spring-expression-4.2.0.RELEASE.jar 
.m2\repository\org\aspectj\aspectjrt\1.8.6\aspectjrt-1.8.6.jar 
.m2\repository\org\aspectj\aspectjweaver\1.8.6\aspectjweaver-1.8.6.jar 
.m2\repository\org\springframework\spring-test\4.2.0.RELEASE\spring-test-4.2.0.RELEASE.jar 
.m2\repository\javax\inject\javax.inject\1\javax.inject-1.jar 
/C:/eclipse/configuration/org.eclipse.osgi/bundles/201/1/.cp/ 
/C:/eclipse/configuration/org.eclipse.osgi/bundles/200/1/.cp/ 

Edit 2: ich Dinge wurden durch die Arbeit JUnit4 Entfernen von der Registerkarte Bibliotheken in Configure-Erstellungspfad.

Antwort

3

Der folgende Test funktioniert gut, mit Spring 3.0 oder höher (getestet mit Feder 3.0.7, 4.0.5 und 4.2.0):

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = "classpath:beans.xml") 
public class MainActionTest 
{ 
    @Inject MainAction mainAction; 

    @Test 
    public void testThatLoggerIsCalled(@Mocked final Logger logger) 
    { 
     mainAction.doTheAction(); 

     new Verifications() {{ logger.log(anyString); }}; 
    } 
} 
+0

Ich bekomme immer noch 'Method testThatLoggerIsCalled sollte keine Parameter haben'. Ich benutze Spring 4.1.0 - versuchte 4.2.0 auch. Außerdem habe Eclipse meine JUnit als 3.8.1 eingerichtet - brauche ich eine spätere Version? Verwenden Sie @Inject von 'javax.inject' oder woanders? – ajb

+0

Dieser Fehler über "habe keine Parameter" tritt auch bei mir auf, aber * nur *, wenn ich Spring 2.5 verwende, das auf dem alten JUnit 4.4 Test Runner basiert. Die minimale JUnit-Version für JMockit * und * Spring Test 4.1 ist JUnit 4.5; Es kann nicht mit 3.8.1 arbeiten (aber das ist wahrscheinlich etwas anderes - Ihre junit.jar im Runtime-Klassenpfad ist höchstwahrscheinlich JUnit 4.x). –

+0

Ich akzeptiere die Antwort, damit das Kopfgeld nicht abläuft. Aber ich werde weiterhin versuchen, die Versionen richtig zu machen, und ich werde Sie auf dem Laufenden halten. – ajb

2

Ich musste JUnit-Tests nie mit RunWith kommentieren, um JMockit zu verwenden. Von der documentation müssen Sie sicherstellen, dass das jmockit jar vor junits geladen wird oder den javaagent jvm-Parameter hinzufügen. Auf diese Weise können Sie die Tests mit Junit Runner von Spring ausführen und JMockit als Mock-Framework verwenden.

+0

Ja, das sollte funktionieren. Ich kann nur hinzufügen, dass die Instantiierung/Injektion der getesteten Klasse von Spring durchgeführt werden muss, sonst wird der Aspekt nicht funktionieren. Um den injizierten "Logger" zu verspotten, müsste der Test "@ Capturing" anstelle von "@ Injectable" verwenden. –

+0

Es funktioniert nicht für mich. Ich bekomme 'Method testThatLoggerIsCalled sollte keine Parameter haben' (aus SpringJUnit4ClassRunner.java), die ich nicht bekomme, wenn ich' @RunWith (JMockit.class) 'verwende. Ich verwende Maven-Abhängigkeiten, und ich habe 'jmockit' über' junit' in pom.xml (eigentlich ist 'jmockit' jetzt zuerst) verschoben und das Projekt gereinigt und neu aufgebaut. Was habe ich sonst noch vergessen? – ajb

+0

@ Rogério Ich kann es immer noch nicht zur Arbeit bringen (siehe vorheriger Kommentar). – ajb