使用JUnit对akka actor进行单元测试

时间:2015-09-30 21:50:52

标签: java akka

最近我试图为akka演员编写一些单元测试来测试演员的消息流。我在测试中发现了一些奇怪的行为:

字段:

private TestActorRef<Actor> sut;
private ActorSystem system;


JavaTestKit AnotherActor;
JavaTestKit YetAnotherActor;

系统和演员是在@Before带注释的方法中创建的:

@Before
public void setup() throws ClassNotFoundException {
    system = ActorSystem.apply();

    AnotherActor = new JavaTestKit(system);
    YetAnotherActor  = new JavaTestKit(system);


    Props props = MyActor.props(someReference);

    this.sut = system.of(props, "MyActor"); }                 

下一步

@Test
public void shouldDoSth() throws Exception {
    // given actor
    MyActor actor = (MyActor) sut.underlyingActor();

    // when 
    SomeMessage message = new SomeMessage(Collections.emptyList());
    sut.tell(message, AnotherActor.getRef());

    // then
    YetAnotherActor.expectMsgClass(
        FiniteDuration.apply(1, TimeUnit.SECONDS),
        YetSomeMessage.class);

}

在我的代码中,我有:

private void processMessage(SomeMessage message) {
    final List<Entity> entities = message.getEntities();
    if(entities.isEmpty()) {
        YetAnotherActor.tell(new YetSomeMessage(), getSelf());
        // return;
    }

    if (entities > workers.size()) {
        throw new IllegalStateException("too many tasks to be started !");
    }

}

基本上,有时(非常罕见)此类测试失败(在另一个操作系统上),并且抛出了processMessage方法的异常(由于业务逻辑导致IllegalStateException)。

主要是测试传递,因为YetAomeMessage消息被YetAnotherActor接收,尽管IllegateStateException错误也被抛出并记录在堆栈跟踪中。

正如我从akka TestActorRef文档中假设的那样:

  

这个特殊的ActorRef专门用于单线程环境中的单元测试。因此,它     将调度程序覆盖到CallingThreadDispatcher并将receiveTimeout设置为None。除此以外,     它的行为就像一个普通的ActorRef。您可以检索对底层actor的引用以测试内部逻辑。

我的系统只使用单线程来处理actor收到的消息。有人可以解释我为什么尽管有适当的断言,测试失败了吗?

当然,在使用正确的代码发送YetSomeMessage之后返回将会完成但我不明白另一个线程处理如何导致测试faiulre。

1 个答案:

答案 0 :(得分:2)

由于您使用的是TestActorRef,因此您基本上在进行同步测试。作为一般经验法则,除非确实需要,否则不要使用TestActorRef。那个东西使用CallingThreadDispatcher,即它会窃取调用者线程来执行actor。因此,您的谜团的解决方案是,actor与测试运行在同一个线程上,因此异常最终会出现在测试线程上。

幸运的是,你的这个测试用例根本不需要TestActorRef。您可以将actor设置为普通的actor,并且一切都应该工作(即actor应该在一个适当的单独线程上)。请尝试使用异步测试支持http://doc.akka.io/docs/akka/2.4.0/scala/testing.html#Asynchronous_Integration_Testing_with_TestKit

执行所有操作