繁体   English   中英

单元测试Akka中的私有方法

[英]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我要么:

  1. 需要它来使包私有
  2. 或测试actor的公共接口,即下一个actor LogWriter从我的actor LogRowParser收到正确的解析消息

我的问题:

  1. 选项#1有任何缺点吗? 假设演员只通过消息进行通信,封装和干净的开放接口不太重要?
  2. 如果我尝试使用选项#2,有没有办法捕获从测试下游的actor发送的消息(测试LogRowParser并捕获LogWriter )? 我回顾了JavaTestKit上的各种示例,但是所有这些示例都捕获了回复给发送者的消息,没有一个会显示如何拦截发送给新actor的消息。
  3. 我还缺少另一种选择吗?

谢谢!

UPD:忘记提及我也考虑过以下选项:

  • 将演员的逻辑完全转移到辅助类中。 这是akka的常见做法吗?
  • Powermock ......但如果可以重新设计,我试图避免它

没有充分理由将该方法设为私有。 一个人通常在类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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM