前言 首先,我们需要了解如何测试发送和接受消息,包括发送然后不管的模式以及发送之后等待回复的交互式模式。
使用的是 Scala 的测试框架 [ScalaTest]。这个框架被设计成可读性性很高。
使用这个工具可以生成可读性很强的测试报告。当然 Akka 也为我们提供了测试工具 akka-test,如果没有这个工具,
我们将面临相比与正常对象更加困难的测试环境。主要有下面四个原因: - 无法准确把握消息到达时间,因为消息是异步发送的
- 并发,Actors 之间是并发多线程的,需要考虑更多的问题,如锁、障碍等
- 无状态 Actor是无法直接访问对象的,只能通过 ActorRef
- 集成测试。如果需要集成测试多个 Actor 就需要在它们直接做拦截,这也是不明确如何去实现的
下面主要从两个方面演示如何利用 akka-testkit + ScalaTest 作测试: - Single threaded unit testing
- Multi-threaded unit testing
环境搭建安装 jdk + sbt + scala, build.sbt 中加入如下内容: - name := "testdriven" #名字随意取,项目名称
- version := "0.1-SNAPSHOT"
- organization := "com.manning" #公司域名倒过来写,最后可以加入部门简称
- scalaVersion := "2.11.7"
- libraryDependencies ++= {
- val akkaVersion = "2.3.12"
- Seq(
- "com.typesafe.akka" %% "akka-actor" % akkaVersion, #注意两个 %% 号的用法基本类
- "com.typesafe.akka" %% "akka-slf4j" % akkaVersion, #日志类
- "com.typesafe.akka" %% "akka-testkit" % akkaVersion % "test", #最后一个 %指定使用范围
- "org.scalatest" %% "scalatest" % "2.2.4" % "test"
- )
- }
复制代码 静态测试示例1- package packagename
- import org.scalatest.WordSpecLike
- import org.scalatest.MustMatchers
- import akka.testkit.{ TestActorRef, TestKit }
- import akka.actor._
- package silenttest {
- class SilentActorTest extends TestKit(ActorSystem("testsystem"))
- with WordSpecLike
- with MustMatchers
- with StopSystemAfterAll {
- "A Silent Actor" must {
- "change internal state when it receives a message, single" in {
- import SilentActor._
- // 利用TestActorRef 直接生成可以访问实际 Actor 对象的 Actor
- val silentActor = TestActorRef[SilentActor]
- silentActor ! SilentMessage("whisper")
- // 静态的测试方法,直接访问actor的内部对象
- silentActor.underlyingActor.state must (contain("whisper"))
- }
- //<end id="ch02-silentactor-test02"/>
- }
- }
- object SilentActor {
- case class SilentMessage(data: String)
- case class GetState(receiver: ActorRef)
- }
- class SilentActor extends Actor {
- import SilentActor._
- var internalState = Vector[String]()
- def receive = {
- case SilentMessage(data) =>
- internalState = internalState :+ data
- }
- def state = internalState
- }
- }
- //通用类,目的是及时关闭所有Actor
- package common {
- import akka.testkit.TestKit
- import org.scalatest.{Suite, BeforeAndAfterAll}
- trait StopSystemAfterAll extends BeforeAndAfterAll{
- //注意这种混入手法
- this: TestKit with Suite =>
- override protected def afterAll(): Unit = {
- super.afterAll()
- system.shutdown()
- }
- }
- }
复制代码 静态测试示例2
- package silentactor03 {
- class SilentActorTest extends TestKit(ActorSystem("testsystem"))
- with WordSpecLike
- with MustMatchers
- with StopSystemAfterAll {
- "A Silent Actor" must {
- "change internal state when it receives a message, multi" in {
- import SilentActor._
- val silentActor = system.actorOf(Props[SilentActor], "s3")
- silentActor ! SilentMessage("whisper1")
- silentActor ! SilentMessage("whisper2")
- //通过发送消息获取内部状态
- silentActor ! GetState(testActor)
- expectMsg(Vector("whisper1", "whisper2"))
- }
- }
- }
- object SilentActor {
- case class SilentMessage(data: String)
- case class GetState(receiver: ActorRef)
- }
- class SilentActor extends Actor {
- import SilentActor._
- var internalState = Vector[String]()
- def receive = {
- case SilentMessage(data) =>
- internalState = internalState :+ data
- case GetState(receiver) => receiver ! internalState
- }
- }
- }
复制代码
|