2013-05-23 39 views
12

Tôi muốn biết về cách để kiểm tra chức năng diễn viên Akka, bởi chế giễu một số phương pháp (thực hiện phương pháp thay thế thực của đối tượng/diễn viên bằng cách chế giễu một) trong diễn viên.Làm thế nào để kiểm tra chức năng diễn viên Akka bởi chế giễu một hoặc nhiều biện pháp trong đó

Tôi sử dụng akka.testkit.TestActorRef;

Ngoài ra: Tôi đã cố gắng sử dụng SpyingProducer nhưng không rõ cách sử dụng. (giống như tôi nếu tôi tạo ra diễn viên bên trong việc thực hiện nó, nó sẽ giống như tôi hiện có). Kết quả tìm kiếm trên google về điều đó không phải là rất verbose.

Tôi sử dụng powemockitojava. Nhưng nó không quan trọng. Tôi sẽ được quan tâm để biết how to do it in principlevới bất kỳ ngôn ngữ với bất kỳ khuôn khổ

(vì vậy nếu bạn không biết cách điện/Mockito công trình chỉ cung cấp mã của bạn .. (xin) hoặc ý tưởng đầy đủ về cách bạn sẽ . làm điều đó với công cụ của bạn, bạn biết)

Vì vậy, giả sử chúng ta có một diễn viên để kiểm tra:

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; 
    } 

} 

Và trong thử nghiệm của chúng tôi, chúng tôi muốn thay getHelloMessage() trả lại thứ gì đó khác.

Đây là cố gắng của tôi:

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"); 
     } 
    } 
} 

Kết quả:

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

Trả lời

1

Vì vậy, tôi có lẽ không hiểu câu hỏi nhưng có thể bạn không muốn thử một diễn viên như mục đích của mocking là thay thế thứ gì đó như dao với bản sao thử nghiệm có kỳ vọng về lời gọi - diễn viên không thực sự phù hợp với hóa đơn vì nó là thứ bạn mở rộng thay vì phụ thuộc - chế nhạo thực sự chỉ áp dụng cho phụ thuộc thực sự.

TestActorRef đặc biệt cung cấp cho bạn quyền truy cập vào diễn viên cơ bản - trong hầu hết các trường hợp bình thường, bạn chỉ có thể gửi tin nhắn cho một diễn viên và không gọi trực tiếp bất kỳ điều gì. TestActoRef loại bỏ giới hạn này bằng cách cho phép bạn truy cập phần mở rộng thực sự thực sự của diễn viên thay vì chỉ ActorRef mà bạn chỉ có thể! hoặc là ? chống lại (gửi hoặc hỏi).

Tôi là nhà phát triển scala nên thông tin chi tiết hy vọng là không thuyết phục. Tôi không biết java api cụ thể nhưng nó không quan trọng.

Đề xuất của tôi là để có được đối tượng Actor thực thông qua diễn viên ref và chỉ cần kiểm tra phương pháp hoặc tìm ra một số cách để có được phạm vi kiểm tra thông qua tin nhắn thực sự.

+0

Làm thế nào bạn kiểm tra nó trong scala? chế nhạo ở đây có nghĩa là - để giả lập một phương pháp. tức là thay thế một phương thức trên đối tượng thực (đó là lý do chúng ta sử dụng spy() - để có thể thực hiện phương thức của chúng ta - cho phép phương thức biết trả về cho các tham số của phương thức cụ thể và không sử dụng cơ thể thực của phương thức trong onReceive () nhưng chế giễu một). "TestActorRef đặc biệt cung cấp cho bạn quyền truy cập vào diễn viên cơ bản" - đó là lý do tại sao tôi muốn sử dụng diễn viên này, nhưng không gửi thông điệp. Mocking và Spying là thực hành chung cho Java, và trong trường hợp này nó không hoạt động, mặc dù chúng ta có quyền truy cập vào diễn viên obj – ses

+0

Và tại sao những kẻ scala tự hào đến mức họ biết scala nhưng không biết java? (không có hành vi phạm tội) :) – ses

+0

Tôi biết java tốt hơn tôi biết scala - chỉ cần không phải là java java aki! – JasonG

10

Akka có một lớp AutoPilot về cơ bản là một mô hình chung cho các diễn viên, với khả năng trả lời thư và xác nhận rằng thư đã được gửi. http://doc.akka.io/docs/akka/snapshot/java/testing.html

Đây là ví dụ java cho trang đó. Bạn tạo một thăm dò, thiết lập một phi công tự động có thể trả lời tin nhắn, và nhận được một ActorRef từ nó mà bạn có thể thay thế cho cho diễn viên thực sự của bạn.

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 để cập nhật. Tôi sẽ chơi với cái sau. sẽ thấy nóng nó phù hợp với nhu cầu của tôi/sự hiểu biết nó như thế nào. – ses

2

Tôi không có kinh nghiệm sử dụng Akka với Java, nhưng tôi đoán giải pháp cho điều này tôi sử dụng trong Scala cũng có thể áp dụng cho Java. Không cần thiết phải chế giễu gì cả. Trong Java chế nhạo đôi khi rất hữu ích để thử nghiệm, nhưng kinh nghiệm cá nhân của tôi/ý kiến ​​là bất cứ khi nào bạn cần PowerMock bạn đang làm điều gì đó sai trái.

Đây là cách tôi cố gắng để kiểm tra sử dụng Akka:

Trong Scala tôi sử dụng một đặc điểm (giao diện aka), trong đó các phương pháp diễn viên được xác định.

trait ToBeTested { 
    def getHelloMessage(msg: String, replyTarget: ActorRef): String = 
     replyTarget ! s"Hello $msg" 
} 

Bằng cách này, chức năng này có thể được kiểm tra đơn vị rất dễ dàng. Đối với các diễn viên thực sự tôi cố gắng gắn bó để thực hiện phương thức nhận chỉ.

class ToBeTestedActor extends Actor with ToBeTested { 
    def receive: Receive = { 
    case msg: String => getHelloMessage(msg, sender()) 
    } 
} 

Sau đó, khi thử nghiệm diễn viên, bạn có thể ghi đè triển khai getHelloMessage để làm bất cứ điều gì bạn muốn.

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) 
} 

Trong Java, bạn có thể làm khá nhiều điều tương tự. Vì Java 8, bạn có thể cung cấp các triển khai phương thức mặc định trong các giao diện, mà bạn có thể ghi đè trong một giao diện con để thử nghiệm. Một cách khác sẽ là để phân lớp các diễn viên trong thử nghiệm của bạn để ghi đè lên một số phương pháp để cung cấp hành vi dự đoán được.

// 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.