3

Ich versuche, Spring zu bekommen, um EasyMock Mocks in meine Komponententests injizieren.Verwenden von Spring zu injizieren EasyMock Mocks verursacht ClassCastException

In meinem applicationContext.xml, ich habe dies:

<bean id="mockService" class="org.easymock.EasyMock" factory-method="createMock" name="MockService"> 
    <constructor-arg index="0" value="my.project.Service"/> 
</bean> 

In meinem Unit-Test ich diese:

@Autowired 
@Qualifier("mockService") 
private Service service; 

public void testGetFoo() { 
    Foo foo = new Foo(); 

    expect(service.findFoo()).andReturn(foo); 
    replay(service); // <-- This is line 45, which causes the exception 

    // Assertions go here... 
} 

Wenn ich versuche, meinen Test auszuführen, erhalte ich diesen Stack-Trace:

java.lang.ClassCastException: org.springframework.aop.framework.JdkDynamicAopProxy 
at org.easymock.EasyMock.getControl(EasyMock.java:1330) 
at org.easymock.EasyMock.replay(EasyMock.java:1279) 
at TestFooBar.testGetFoo(TestVodServiceLocator.java:45) 

ich bin ganz neu sowohl auf Frühling und EasyMock, aber es scheint mir, dass der Fehler durch EasyMock verursacht wird versucht, ein mir anrufen thod auf, was es annimmt, eine Instanz von EasyMock zu sein, aber in Wirklichkeit ein dynamischer Proxy ist, der von Frühling geschaffen wird. Wie ich es verstehe, implementieren dynamische Proxys nur die Methoden, die in der Schnittstelle definiert sind, in diesem Fall die Schnittstelle für Service.

Was ich nicht verstehe ist, dass from what I read (auch here), was ich versuche zu erreichen zumindest scheint möglich zu sein.

Also meine Frage ist: Was ich mache ich nicht oder was mache ich falsch?

Antwort

4

Gelöst!

ich in meinem applicationContext.xml übersehen dies hatte:

<bean id="txProxyAutoCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
    <property name="beanNames"> 
     <list> 

      <value>*Service</value> 
      <!-- ^^^^^^^^  
       This is the problem! 
      --> 
     </list> 
    </property> 
    <property name="interceptorNames"> 
     <list> 
      <value>txAdvisor</value> 
     </list> 
    </property> 
</bean> 

... die Feder bewirkt, dass automatisch Proxy-Objekte für alle Bohnen mit Namen erstellen, die in „Service“ zu beenden.

Meine Lösung war, die Beans explizit aufzulisten, anstatt eine Platzhalterkarte zu verwenden. Das scheint mir allerdings ein wenig spröde, wenn also jemand weiß, wie man alle * Servicebohnen außer FooService angeben kann, wäre ich dankbar.

1

Etwas ist hier merkwürdig. Sie beherrschen ganz klar sowohl Spring als auch EasyMock. Die Autoproxies, die Fabrikmethoden, alles gute Zeichen, dass Sie tief in Spring's Fähigkeiten eintauchen.

Dennoch ist es merkwürdig, dass Sie überhaupt eine Mock-Bean in eine Klasse injizieren. Sie haben vielleicht einen guten Grund, aber für mich ist es ein Code-Geruch. Ich rate Ihnen, nur die Verkabelung in realen Diensten in Ihre Testklassen zu integrieren und dann die Mock-Objekte nach Bedarf zu initialisieren. Warum drei Zeilen in Java und weitere drei Zeilen in XML ausgeben (plus eine Zeile, um sie zurückzusetzen), um ein Mock-Objekt ohne Abhängigkeiten zu erstellen? Sagen Sie einfach Service service = (Service) createMock (Service.class). Ich würde empfehlen, sie in den Methoden zu erstellen, für die sie benötigt werden, Erwartungen festzulegen, sie zu injizieren, zu verwenden und dann zu verwerfen. In Ihrem Modell müssen Sie daran denken, das Mock-Objekt jedes Mal neu zu setzen, wenn Sie es verwenden, was weniger klar ist, als nur ein neues zu erstellen.

Natürlich ist dies ein Stilproblem und kein Korrektheitsproblem, also ignorieren Sie es wie gewünscht. erwartete Verhalten

+0

Ich habe mein Beispiel vor dem Posten etwas vereinfacht, um es einfacher zu verstehen. Die Sache ist, dass die getestete Klasse dafür verantwortlich ist, eine bestimmte Bean aus dem Anwendungskontext zur Laufzeit basierend auf ihrem Namen zu bekommen. Es schien naheliegend, diese Bean als Mock in der XML-Datei zu definieren. Immer noch verstehe ich Ihren Standpunkt, und Sie haben Recht. Ich glaube, ich habe ein paar Dinge gemischt und ein bisschen zu weit gegangen. – KaptajnKold

+0

Dies wird nützlich, wenn Sie die Ausführung oder Verdrahtung eines Integrationstests durchführen möchten. Auf diese Weise können Sie z.B. Überprüfen Sie, ob Transaktionen korrekt angewendet werden. –

6

Sie können auch eine Hilfsmethode erstellen die EasyMock Proxy aus der Frühjahr-Proxy auszupacken dann zu definieren:

public static <T> T unwrap(T proxiedInstance) { 
    if (proxiedInstance instanceof Advised) { 
    return unwrap((T) ((Advised) proxiedInstance).getTargetSource().getTarget()); 
    } 

    return proxiedInstance; 
} 

Notiere die recusive Anruf als im schlimmsten Fall haben Sie mehrere Proxys um das eigentliche Ziel gewickelt .

+0

Ich mag diese Methode wirklich! –

+0

Ich wünschte ich hätte mehr Upvotes –

1

Ich weiß, diese Frage ist alt, aber ich stolperte gerade über die Suche nach einem ähnlichen Problem.

Das Problem ist, dass Spring den Typ des Mock-Objekts nicht kennt. Die verwendete Methode sieht wie folgt aus:

public static <T> T createMock(final Class<T> toMock) { 
    return createControl().createMock(toMock); 
} 

Frühling nicht intelligent genug ist T aus dem Konstruktorargument abzuleiten (zumindest ich das letzte Mal überprüft haben), so denkt, dass es das zurückgegebene Objekt ist vom Typ java.lang.Object . Der implementierte Proxy implementiert daher my.project.Service nicht und kann daher nicht injiziert werden.

Die Antwort lautet daher, Spring den erforderlichen Typ mitzuteilen.

Verwandte Themen