简体   繁体   English

如何同步对akka Actor进行单元测试?

[英]How do I unit test an akka Actor synchronously?

I've got an actor that will write a file after receiving a certain number of messages. 我有一个演员在收到一定数量的消息后会写一个文件。

When compiling, Maven runs all the unit tests we have defined. 编译时,Maven运行我们定义的所有单元测试。 The problem is that the unit test to check that the file was successfully written to disk happens before the Actor writes the file (which it does correctly). 问题是,在Actor写入文件(它正确执行)之前,检查文件是否已成功写入磁盘的单元测试。

I've found some documentation for testing Actors, but they're all out of date by several years. 我找到了一些测试Actors的文档,但它们都已经过了好几年了。 How can I wait for a bit before checking that the file exists? 在检查文件是否存在之前,我该如何等待?

Just to sum up all comments and suggestions: 只是总结所有意见和建议:

  • Refactor non-actor specific code to regular classes and test it using regular means (unit tests, etc). 将非actor专用代码重构为常规类,并使用常规方法(单元测试等)对其进行测试。 This is more of a unit test approach. 这更像是一种单元测试方法。
  • Use TestActorRef to test a single actor - you can control events synchronously and rich into actor internals. 使用TestActorRef测试单个actor - 您可以同步控制事件并丰富到actor内部。 Use TestKit which provides much more including "special" actor system. 使用提供更多功能的TestKit,包括“特殊”演员系统。 This is more of a behavioural test approach. 这更像是一种行为测试方法。
  • Use documentation here to learn more about how Akka TestKit works but in short you get control over your actor and synchronous execution. 使用此处的文档来了解有关Akka TestKit如何工作的更多信息,但总之,您可以控制您的actor和同步执行。

For synchronous actor testing, use TestProbes (akka.testkit) similar to this: 对于同步actor测试,使用类似于此的TestProbes(akka.testkit):

import org.scalatest.{FunSuite, BeforeAndAfterAll}
import org.scalatest.matchers.ShouldMatchers
import scala.concurrent.duration._
import scala.util.Random
import scala.util.control.NonFatal
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
import akka.actor.{ActorSystem, ActorRef, Actor, Props}
import akka.testkit.{TestKit, ImplicitSender, TestProbe}
import scala.concurrent._
import ExecutionContext.Implicits.global

@RunWith(classOf[JUnitRunner])
class Example extends TestKit(ActorSystem("filetest"))
  with FunSuite
  with BeforeAndAfterAll
  with ShouldMatchers
  with ImplicitSender
  with Tools {

  override def afterAll(): Unit = {
    system.shutdown()
  }

  test("Show synchronous actor test") {
    val tester = TestProbe()
    val fileActor = system.actorOf(Props(classOf[FileActor]), "case2-primary")

    tester.send(fileActor, CreateFile(1))
    tester.expectMsg(FileCreated(1)) // Will synchronously wait (~500ms in this example)
  }
}

case class CreateFile(id: Long)
case class FileCreated(id: Long)

class FileActor extends Actor {
  def receive = {
    case CreateFile(id) => {
      val s = sender
      createFile(id).map( id => s ! FileCreated(id))
    }
  }

  def createFile(id: Long): Future[Long] = future {
    // "Create" the file...
    Thread.sleep(500)
    id
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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