我是akka的新手,我在java上尝试akka。我想了解演员内部业务逻辑的单元测试。我读了documentation,演员中唯一的隔离业务逻辑示例是:
static class MyActor extends UntypedActor {
public void onReceive(Object o) throws Exception {
if (o.equals("say42")) {
getSender().tell(42, getSelf());
} else if (o instanceof Exception) {
throw (Exception) o;
}
}
public boolean testMe() { return true; }
}
@Test
public void demonstrateTestActorRef() {
final Props props = Props.create(MyActor.class);
final TestActorRef<MyActor> ref = TestActorRef.create(system, props, "testA");
final MyActor actor = ref.underlyingActor();
assertTrue(actor.testMe());
}
虽然这很简单,但这意味着我想测试的方法是公开的。但是,考虑到演员应该只通过消息进行交流,我理解没有理由采用公开方法,因此我将我的方法设为私有。如下例所示:
public class LogRowParser extends AbstractActor {
private final Logger logger = LoggerFactory.getLogger(LogRowParser.class);
public LogRowParser() {
receive(ReceiveBuilder.
match(LogRow.class, lr -> {
ParsedLog log = parse(lr.rowText);
final ActorRef logWriter = getContext().actorOf(Props.create(LogWriter.class));
logWriter.tell(log, self());
}).
matchAny(o -> logger.info("Unknown message")).build()
);
}
private ParsedLog parse(String rowText) {
// Log parsing logic
}
}
所以测试方法parse
我要么:
LogWriter
从我的演员LogRowParser
收到正确的解析消息我的问题:
LogRowParser
并捕获LogWriter
)?我查看了JavaTestKit
上的各种示例,但所有这些示例都捕获了回复给发送者的消息,没有一个会显示如何拦截发送给新玩家的消息。谢谢!
UPD: 忘了提一下我也考虑了以下选项:
答案 0 :(得分:2)
真的没有理由让这种方法变得私密。一个人通常在类private上创建一个方法,以防止有人直接引用该类的实例来调用该方法。使用actor实例,没有人会直接引用该actor类的实例。您可以与该actor类的实例进行通信的是ActorRef
,它是一个轻量级代理,只允许您通过邮箱发送由onReceive
处理的消息进行通信。 ActorRef
不公开该actor类的任何内部状态或方法。这是演员系统的一大卖点。一个actor实例完全封装了它的内部状态和方法,保护它们不受外界影响,只允许那些内部事物响应接收消息而改变。这就是为什么似乎没有必要将该方法标记为私有。
修改强>
演员IMO的单元测试应始终通过receive
功能。如果你有一些内部方法然后被receive
中的处理调用,你不应该专注于单独测试这些方法,而是确保通过你的消息正确地执行导致它们调用的路径在测试场景中通过。
在您的特定示例中,parse
正在生成ParsedLog
消息,然后将其发送给logWriter
子actor。对我而言,知道parse
按预期工作意味着断言logWriter
收到了正确的消息。为了做到这一点,我将允许覆盖子logWriter
的创建,然后在测试代码中执行该操作,并用TestProbe
替换actor创建。然后,您可以对该探针使用expectMsg
,以确保它收到了预期的ParsedLog
消息,从而也在parse
中测试了该功能。
至于你的其他评论围绕将演员的真实业务转移到一个单独的,更可测试的类,然后从演员那里调用,有些人这样做,所以这并非闻所未闻。我个人没有,但那只是我。如果这种方法适合您,我认为没有任何重大问题。
答案 1 :(得分:0)
3年前,当与演员打交道时,我遇到了同样的问题:我发现最好的方法是对演员负责任的角色负责。 演员将收到该消息并选择要调用的对象方法或要发送的消息或抛出的异常以及它。 这样,模拟actor调用的服务和这些服务的输入将非常简单。