[英]Unit testing private methods in Akka
我是akka的新手,我正在尝试java上的akka。 我想了解演员内部业务逻辑的单元测试。 我阅读文档 ,演员中唯一的隔离业务逻辑示例是:
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
从我的actor LogRowParser
收到正确的解析消息 我的问题:
LogRowParser
并捕获LogWriter
)? 我回顾了JavaTestKit
上的各种示例,但是所有这些示例都捕获了回复给发送者的消息,没有一个会显示如何拦截发送给新actor的消息。 谢谢!
UPD:忘记提及我也考虑过以下选项:
没有充分理由将该方法设为私有。 一个人通常在类private上创建一个方法,以防止有人直接引用该类的实例来调用该方法。 使用actor实例,没有人会直接引用该actor类的实例。 您可以与该actor类的实例进行通信的是ActorRef
,它是一个轻量级代理,只允许您通过发送邮件进行通信,以便通过邮箱由onReceive
处理。 ActorRef
不公开该actor类的任何内部状态或方法。 这是演员系统的一大卖点。 一个actor实例完全封装了它的内部状态和方法,保护它们不受外界影响,只允许那些内部事物响应接收消息而改变。 这就是为什么似乎没有必要将该方法标记为私有。
编辑
演员IMO的单元测试应该始终通过receive
功能。 如果你有一些内部方法然后被receive
处理调用,你不应该专注于单独测试这些方法,而是确保通过你在测试场景中传递的消息正确地执行导致它们调用的路径。
在您的特定示例中, parse
正在生成ParsedLog
消息,然后ParsedLog
消息发送到logWriter
子actor。 对我来说,知道parse
按预期工作意味着断言logWriter
收到了正确的消息。 为了做到这一点,我将允许重写子logWriter
的创建,然后在测试代码中执行该操作,并用TestProbe
替换actor创建。 然后,您可以在该探针上使用expectMsg
以确保它收到预期的ParsedLog
消息,从而也在parse
测试功能。
至于你的其他评论围绕将演员的真实业务转移到一个单独的,更可测试的类,然后从演员那里调用,有些人这样做,所以这并非闻所未闻。 我个人没有,但那只是我。 如果这种方法适合您,我认为它没有任何重大问题。
3年前,当与演员打交道时,我遇到了同样的问题:我发现的最佳方法是对演员负责任的角色负责。 actor将接收消息并选择要调用的Object方法或要发送的消息或抛出异常,就是这样。 这样,模拟actor调用的服务和这些服务的输入将非常简单。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.