2014-09-24 63 views
6

我有一個演員FooActor通過Props實例化幾個BarActor s併發送BarMessage s到它。代碼有效,但我很難爲它編寫測試。額外的限制是我只能在這個應用程序中使用Java代碼,沒有Scala代碼。如何測試Actor Foo向新創建的子actor的Bar發送消息?

多次嘗試後,這似乎是到目前爲止我最大的努力:

@Test 
public void testJavaTestKit() { 

    new JavaTestKit(system) {{ 
     JavaTestKit probe = new JavaTestKit(system); 

     // pretending that the probe is the receiving Bar, by returning it in the Props 
     Props barActorProps = Props.create(BarActor.class, new Creator() { 
      @Override 
      public Object create() { 
       return probe.getRef(); 
      } 
     }); 
     Props props = Props.create(FooActor.class, barActorProps); 
     ActorRef subject = system.actorOf(props); 

     Object msg = // basically irrelevant, will trigger Bar instantiation and message sending 

     subject.tell(msg, probe.getRef()); 

     expectMsgClass(Bar.BarMessage.class); 
     expectNoMsg(); 
    }}; 
} 

這一切都似乎是有道理的我,但即使我能看到的消息發送到新創建的Bar情況下,第一個斷言失敗。我究竟做錯了什麼?

更新:

,使得從阿卡文檔例如,這不同的東西,是我不想通過接收消息的現有演員。相反,我想通過用於創建子actor的實例的Props。在測試中,我想讓我的probe接收消息給那些新創建的演員。這就是爲什麼我添加Props.create構造,應始終返回相同的探測器參與者。剛纔我在Creator.create API中看到這條評論:

此方法在每次調用時都必須返回一個不同的實例。

所以這顯然不起作用,因爲它正是我想要的。所以我的一般問題仍然存在:我如何測試發送給新創建的子actor的消息?

+2

探測器JavaTestKit ActorRef您希望發送消息的位置?如果是這樣,您需要調用probe.expectMsgClass,目前您在測試方法中針對匿名JavaTestKit進行斷言。除非你的測試「主題」用Bar.BarMessage.class回覆,那麼該斷言總是會失敗 – nickebbitt 2014-09-24 20:06:16

+2

解決方案可能與將斷言更改爲'probe.expectMsgClass(Bar.BarMessage.class);' – nickebbitt 2014-09-24 20:10:54

+0

感謝您的回答。這看起來很有前途,它可能使我更接近解決方案,儘管目前它還沒有工作。 – 2014-09-25 09:07:47

回答

4

您試圖「欺騙」兒童演員如何初始化(通過probeRef)以靈活地測試它們,但問題在於即使Creator是通用的,在標準環境中使用getContext().actorOf(),無法返回ActorRef作爲create方法的結果。合同需要始終如下Creator<T extends Actor>

請看看ActorCreationTest

,因爲,我不知道您的FooActor實現我可能是錯的,但如果你將使用stadard模式getContext().actorOf()默認阿卡akka.actor.CreatorConsumer不會接受你的Consumer

caused by: java.lang.ClassCastException: akka.actor.RepointableActorRef cannot be cast to akka.actor.Actor 
    at akka.actor.CreatorConsumer.produce(Props.scala:335) 
    at akka.actor.Props.newActor(Props.scala:252) 
    at akka.actor.ActorCell.newActor(ActorCell.scala:552) 
    at akka.actor.ActorCell.create(ActorCell.scala:578) 
    ... 9 more 

,而不是返回ActorRef探測您可以嘗試返回匿名轉發Actor的?

import akka.actor.*; 
import akka.japi.Creator; 
import akka.testkit.JavaTestKit; 
import org.junit.Test; 

public class ActorTest { 

    @Test 
    public void testJavaTestKit() { 
     ActorSystem system = ActorSystem.create("Acceptor"); 

     new JavaTestKit(system) {{ 
      JavaTestKit probe = new JavaTestKit(system); 

      Creator creator =() -> new UntypedActor() { 
       @Override 
       public void onReceive(Object message) throws Exception { 
        probe.getRef().tell(message, sender()); 
       } 
      }; 


      ActorRef subject = system.actorOf(Props.create(FooActor.class, creator)); 

      subject.tell(new Bar().new BarMessage(), probe.getRef()); 
      probe.expectMsgClass(Bar.BarMessage.class); 


     }}; 
    } 

} 


class BarActor extends UntypedActor { 

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

    } 
} 

class FooActor extends UntypedActor { 

    ActorRef barRef; 

    public static Props props(final Creator creator) { 
     return Props.create(FooActor.class,() -> new FooActor(creator)); 
    } 
    public FooActor(Creator creator) { 
     barRef = getContext().actorOf(Props.create(creator),"bar"); 
    } 

    @Override 
    public void onReceive(Object message) throws Exception { 
     barRef.tell(message,sender()); 
    } 
} 

class Bar { 
    class BarMessage { 

    } 
} 
1

我覺得像這樣的東西應該適合您的情況。

class ActorSpec extends Specification { 
    @Shared 
    private ActorSystem system 
    @Shared 
    private ActorRef actorRef 
    def setupSpec() { 
     system = ActorSystem.create("test-system",ConfigFactory.load("application.conf")) 
    } 
    def "Verify message received"() { 
    given: 
      JavaTestKit probe = new JavaTestKit(system) 
      final Props props = Props.create(BarActor.class) 
      actorRef = system.actorOf(props) 
     when: 
      actorRef.tell(new BarMessage(), probe.getRef()) 
     then: 
      probe.expectMsgClass(Bar.BarMessage.class); 
    } 
def cleanupSpec() { 
     JavaTestKit.shutdownActorSystem(system) 
     system = null 
    } 
相關問題