ScalaInAction測試——靜態測試

ScalaInAction測試——靜態測試

前言

首先,咱們須要瞭解如何測試發送和接受消息,包括髮送而後無論的模式以及發送以後等待回覆的交互式模式。
使用的是 Scala 的測試框架 [ScalaTest]http://www.scalatest.org/。這個框架被設計成可讀性性很高。
使用這個工具能夠生成可讀性很強的測試報告。固然 Akka 也爲咱們提供了測試工具 akka-test,若是沒有這個工具,
咱們將面臨相比與正常對象更加困難的測試環境。主要有下面四個緣由:多線程

  1. 沒法準確把握消息到達時間,由於消息是異步發送的
  2. 併發,Actors 之間是併發多線程的,須要考慮更多的問題,如鎖、障礙等
  3. 無狀態 Actor是沒法直接訪問對象的,只能經過 ActorRef
  4. 集成測試。若是須要集成測試多個 Actor 就須要在它們直接作攔截,這也是不明確如何去實現的

下面主要從兩個方面演示如何利用 akka-testkit + ScalaTest 做測試:併發

  1. Single threaded unit testing
  2. 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 
    }
  }
}

參考文獻

scala in action異步

相關文章
相關標籤/搜索