【问题标题】:Testing an actors that creates child actors测试创建子演员的演员
【发布时间】:2021-02-11 14:43:09
【问题描述】:

例如,我有两个演员——一个父演员和一个子演员。当父母收到一条消息时,它会产生与消息中指定的一样多的子actor。如何测试此功能?有没有办法模拟上下文或其他方法来检查演员是否正确创建且数量正确?

class ParentActor extends Actor {
  case class CreateChildren(count: Int)

  override def receive: Receive = {
    case CreateChildren(count) => for (_ <- 0 until count) context.actorOf(Props[ChildActor])
  }
}

class ChildActor extends Actor {
  override def receive: Receive = {
    case _ =>
  }
}

更新:基于@Tim 回答的解决方案

更改的课程:

class ParentActor(childActorFactory: ChildActorFactory) extends Actor {
  override def receive: Receive = {
    case CreateChildren(count) => for (_ <- 0 until count) childActorFactory.create(context)
  }
}

object ParentActor {
  def props(childActorFactory: ChildActorFactory): Props = Props(new ParentActor(childActorFactory))
}

class ChildActorFactory {
  def create(context: ActorContext): ActorRef = context.actorOf(Props[ChildActor])
}

测试:

"ParentActor" should {
    "instantiate ten child actors" in {
      val childrenCount = 10
      val childActorFactory = mock[ChildActorFactory]
      val parentActor = TestActorRef[ParentActor](ParentActor.props(childActorFactory))

      parentActor ! CreateChildren(childrenCount)

      Mockito.verify(childActorFactory, Mockito.times(childrenCount))
        .create(parentActor.underlyingActor.context)
    }
  }

【问题讨论】:

  • 为什么要创作这么多演员?你不想对其中之一做context.become 吗?您确定只想创建它们吗?
  • @TomerShetah 单独的actor异步运行,允许更大的并行性,而使用context.become是串行的。这也允许状态在子角色中本地化,而不是在父角色中集中。
  • @Tim,据我所知,在您将它们添加到上下文之前,它们根本不会被调用。远的例子,如果你在ChildActor接收函数中添加:case s =&gt; println(s),并发送一个字符串到ParentActor,它不会被解析。
  • @TomerShetah 这是为支持有关演员创建和测试的特定问题而提供的伪代码,因此不要过多解读代码不完整的事实。

标签: scala unit-testing akka


【解决方案1】:

如果你想完全测试父actor,你需要mock子actor,所以你不能直接在父actor中创建子actor。相反,将工厂方法传递给父actor(依赖注入):

class ParentActor(makeChild: () => ChildActor) extends Actor {
  case class CreateChildren(count: Int)

  override def receive: Receive = {
    case CreateChildren(count) => for (_ <- 0 until count) makeChild() 
  }
}

makeChild 函数可以计算创建的 Actor 的数量。它还可以返回 ChildActor 的模拟版本,该版本实现了测试行为以对 ParentActor 施加压力。

【讨论】:

  • 谢谢!我根据您的回答扩展了我的代码,一切正常。
【解决方案2】:

确保创建子 Actor 的最简单方法是覆盖 ChildActor 中的 preStart() 方法

class ChildActor extendsActor with ActorLogging {
  override def preStart(): Unit = log.info("Child created")
def receive(): Receive = // whatever
}

因此,每次将子角色添加到系统时,您都会看到该消息。

【讨论】:

  • 是的,但此解决方案需要手动检查日志。我需要一个用于自动验证的单元测试,所以这个解决方案是绝对不合适的。
猜你喜欢
  • 1970-01-01
  • 2013-12-26
  • 2014-03-09
  • 1970-01-01
  • 1970-01-01
  • 2015-09-25
  • 2013-09-02
  • 2010-10-03
  • 2015-07-24
相关资源
最近更新 更多