2013-05-23 4 views
12

Ich bin daran interessiert zu wissen, wie Akka Darsteller Funktionalität zu testen, durch einige Methoden (Ersatz realen Objekt/der Schauspieler Methode Umsetzung durch verspottet ein spöttischen) in Schauspieler.Wie durch spöttische eine oder mehrere Methoden Akka Schauspieler Funktionalität zu testen darin

Ich verwende akka.testkit.TestActorRef;

Auch: Ich habe versucht, SpyingProducer zu verwenden, aber es ist nicht klar, wie man es benutzt. (Wie ich, wenn ich Schauspieler in seiner Implementierung erstellen würde, wäre es dasselbe, das ich jetzt habe). Das Google-Suchergebnis darüber ist nicht sehr verbose.

Ich verwende powemockito und java. Aber das ist egal. Es würde mich interessieren how to do it in principlemit jeder Sprache zu wissen, mit jedem Rahmen

(also, wenn Sie nicht wissen, wie Kraft/Mockito funktioniert Ihr Code nur zur Verfügung stellen .. (bitte) oder vollständige Vorstellung darüber, wie würden Sie . So tun Sie es mit Ihren Tools, die Sie kennen)

, lassen Sie uns sagen, dass wir einen Schauspieler zu Test haben:

package example.formock; 

import akka.actor.UntypedActor; 

public class ToBeTestedActor extends UntypedActor { 

    @Override 
    public void onReceive(Object message) throws Exception { 

     if (message instanceof String) { 
      getSender().tell(getHelloMessage((String) message), getSelf()); 
     } 

    } 

    String getHelloMessage(String initMessage) { // this was created for test purposes (for testing mocking/spy capabilities). Look at the test 
     return "Hello, " + initMessage; 
    } 

} 

Und in unserem Test wollen wirersetzenetwas anderes zurückgeben. Diese

ist mein Versuch:

package example.formock; 

import akka.testkit.TestActorRef; 
... 

@RunWith(PowerMockRunner.class) 
@PrepareForTest(ToBeTestedActor.class) 
public class ToBeTestedActorTest { 

    static final Timeout timeout = new Timeout(Duration.create(5, "seconds")); 

    @Test 
    public void getHelloMessage() { 

     final ActorSystem system = ActorSystem.create("system"); 

     // given 
     final TestActorRef<ToBeTestedActor> actorRef = TestActorRef.create(
       system, 
       Props.create(ToBeTestedActor.class), 
       "toBeTestedActor"); 

     // First try: 
     ToBeTestedActor actorSpy = PowerMockito.spy(actorRef.underlyingActor()); 
     // change functionality 
     PowerMockito.when(actorSpy.getHelloMessage (anyString())).thenReturn("nothing"); // <- expecting result 


     try { 

      // when 
      Future<Object> future = Patterns.ask(actorRef, "Bob", timeout); 
      // then 
      assertTrue(future.isCompleted()); 

      // when 
      String resultMessage = (String) Await.result(future, Duration.Zero()); 
      // then 
      assertEquals("nothing", resultMessage); // FAIL HERE 

     } catch (Exception e) { 
      fail("ops"); 
     } 
    } 
} 

Ergebnis:

org.junit.ComparisonFailure: 
Expected :nothing 
Actual :Hello, Bob 

Antwort

1

So verstehen Ich bin wahrscheinlich nicht die Frage, aber Sie wollen wahrscheinlich nicht einen Schauspieler als Zweck verspotten Das Mocking besteht darin, etwas wie ein Dao durch eine Testkopie zu ersetzen, die Erwartung von Invokation hat - Schauspieler passt nicht wirklich zur Rechnung, da es eher eine Erweiterung als eine Abhängigkeit ist - Mocking betrifft nur reale Abhängigkeiten.

TestActorRef gibt Ihnen speziell Zugriff auf den zugrunde liegenden Akteur - unter den normalen Umständen können Sie nur Nachrichten an einen Akteur senden und nichts direkt darauf aufrufen. TestActoRef entfernt diese Einschränkung, indem es Ihnen ermöglicht, auf Ihre wahre wahre Erweiterung von Actor zuzugreifen, anstatt nur auf den ActorRef, den Sie nur verwenden können! oder ? gegen (senden oder fragen).

Ich bin ein scala dev so die Einsicht ist hoffnungslos agnostisch. Ich kenne die Java API nicht speziell, aber es sollte nicht wichtig sein.

Meine Empfehlung ist es, das reale Akteurobjekt über Akteurref zu erhalten und die Methode gerade zu prüfen oder eine Weise herauszufinden, um Testabdeckung durch reale Nachrichten zu erhalten.

+0

Wie man es in scala testen würde? Spott bedeutet hier - eine Methode zu verspotten. dh ersetze eine Methode an einem realen Objekt (deshalb benutzen wir spy()), um unsere Implementierung in die Methode einzufügen, um zu wissen, was für bestimmte Methodenparameter zurückzugeben ist und nicht den realen Körper der Methode in onReceive () aber verspottet eins). "TestActorRef gibt Ihnen speziell Zugriff auf den zugrunde liegenden Akteur" - deshalb möchte ich diesen Akteur verwenden, aber keine Nachrichten senden. Mocking und Spioning ist allgemeine Praxis für Java, und in diesem Fall funktioniert es nicht, obwohl wir Zugriff auf Schauspieler obj haben – ses

+0

Und warum scala Jungs so stolz, dass sie scala wissen, aber nicht Java? (nichts für ungut) :) – ses

+0

Ich kenne Java besser als ich scala kenne - nur nicht die akka java api! – JasonG

10

Akka hat eine Klasse AutoPilot, die im Grunde ein allgemeiner Schein für Schauspieler ist, mit der Fähigkeit, auf Nachrichten zu antworten und zu behaupten, dass Nachrichten gesendet wurden. http://doc.akka.io/docs/akka/snapshot/java/testing.html

Hier ist das Java-Beispiel für diese Seite. Sie erstellen ein Probe, legen ein Autopilot fest, das auf Nachrichten antworten kann, und erhalten eine ActorRef davon, die Sie für Ihren echten Schauspieler ersetzen können.

new JavaTestKit(system) {{ 
    final JavaTestKit probe = new JavaTestKit(system); 
    // install auto-pilot 
    probe.setAutoPilot(new TestActor.AutoPilot() { 
    public AutoPilot run(ActorRef sender, Object msg) { 
     sender.tell(msg, ActorRef.noSender()); 
     return noAutoPilot(); 
    } 
    }); 
    // first one is replied to directly ... 
    probe.getRef().tell("hello", getRef()); 
    expectMsgEquals("hello"); 
    // ... but then the auto-pilot switched itself off 
    probe.getRef().tell("world", getRef()); 
    expectNoMsg(); 
}}; 
+0

Thx für das Update. Ich werde mit dem Letzten spielen. werde sehen, dass es meinen Bedürfnissen entspricht/verstehe, wie es sein sollte. – ses

2

Ich habe keine Erfahrung im Umgang mit Akka mit Java, aber ich denke, die Lösung für das ich in Scala kann auch Java anwenden. Es besteht keinerlei Notwendigkeit, irgendetwas zu verspotten. In Java ist das Spotten manchmal nützlich zum Testen, aber meine persönliche Erfahrung/Meinung ist, dass, wenn Sie PowerMock brauchen, Sie etwas falsch machen.

Hier ist, wie ich versuche, Akka zu testen, mit:

In Scala ich eine Eigenschaft (auch bekannt als Interface) verwenden, in denen die Schauspieler Methoden definiert sind.

Auf diese Weise kann diese Funktionalität sehr einfach getestet werden. Für den echten Schauspieler versuche ich nur die Empfangsmethode zu implementieren.

Wenn Sie dann den Actor testen, können Sie die getHelloMessage-Implementierung überschreiben, um das zu tun, was Sie wollen.

class ToBeTestedActorTest extends TestKit(ActorSystem("toBeTested") with .... { 
    trait MyToBeTested extends ToBeTested { 
    // do something predictable for testing or defer to a TestProbe which you can 
    // either define globally in the test class or provide one in a constructor. 
    override def getHelloMessage(msg: String, replyTarget: ActorRef): String = ??? 
    } 

    val toBeTestedActor = TestActorRef(Probe(new ToBeTestedActor with MyToBeTested)) 

    // ... (test cases) 
} 

In Java können Sie so ziemlich dasselbe tun. Seit Java 8 können Sie Standardmethodenimplementierungen in Schnittstellen bereitstellen, die Sie in einer Subschnittstelle zum Testen überschreiben können. Eine andere Möglichkeit wäre, den Akteur in Ihrem Test abzulagern, um einige Methoden zu überschreiben, die vorhersagbares Verhalten bieten.

// An easy unit testable interface 
public interface ToBeTested { 

    public ActorRef self(); 

    default public void getHelloMessage(String msg, ActorRef replyTarget) { 
    replyTarget.tell(String.format("Hello %s", msg), self()); 
    } 
} 

public class ToBeTestedActor extends UntypedActor implements ToBeTested { 

    // self() already implemented by Actor class 

    @Override 
    public void onReceive(Object message) throws Exception { 

    if (message instanceof String) { 
     getHelloMessage((String)message, getSender()); 
    } 
    } 
} 

public class ToBeTestedActorTest { 

    @Test 
    public void test() throws Exception { 
    ActorSystem system = ActorSystem.create(); 

    TestActorRef<Actor> testActorRef = TestActorRef.create(system, Props.create(TestActor.class)); 

    Future<Object> response = Patterns.ask(testActorRef, "World", 1000); 
    assertThat(response.isCompleted(), is(true)); 
    assertThat(Await.result(response, Duration.Zero()), is("Test")); 
    } 

    // Override interface when using Java 8 
    interface DummyToBeTested extends ToBeTested { 
    @Override 
    default void getHelloMessage(String msg, ActorRef replyTarget) { 
     assertThat(msg, is("World")); 
     replyTarget.tell("Test", self()); 
    } 
    } 

    // extend ToBeTestedActor with dummy interface 
    static class TestActor extends ToBeTestedActor implements DummyToBeTested {} 

    // Or (pre Java 8) extend the ToBeTestedActor directly 
    // static class TestActor extends ToBeTestedActor { 
    //  @Override 
    //  public void getHelloMessage(String msg, ActorRef replyTarget) { 
    //   replyTarget.tell("Test", self()); 
    //  } 
    // } 
} 
0
To mock an actor is easier through the TestActorRef. You can use this code : 

    static ActorSystem system = ActorSystem.create(); 
    static Props propsSome = Props.create(MockedResultActor.class); 

    TestActorRef<MockedResultActor> refMockedResultActor= TestActorRef.create(
        system, propsSome, "testA"); 

    // Mocking an actor class and returning our reference actor 
    PowerMockito.mockStatic(ClassToBeMocked.class); 
    Mockito.when(ClassToBeMocked.getToBeMockedMethod()) 
        .thenReturn(refMockedResultActor); 

Note: ClassToBeMocked--Its a class you want to mock. 
MockedResultActor -- Its a class you want to return after mocking. 
This can be run using JunitTest after implementing basic configuration of mocking in your class. Code given here is specific to akka actor in java only.