簡體   English   中英

單元測試scala演員

[英]Unit testing scala actors

有人知道單元測試Scala演員的好方法嗎? 在一般意義上,我有一個接收消息的演員,並會發出其他消息作為回應。 這是在多個線程上完成的,並且不正確的actor可能發送錯誤的消息或根本不發送消息。 我需要一種簡單的方法來創建一個模擬actor,它向正在測試的actor發送和接收消息。 這方面有什么經驗嗎?

由於演員風格的消息傳遞的動態性,模擬演員通常沒有任何麻煩。 只需創建一個接收所需消息的演員即可免費回家。 您當然需要確保這個模擬actor是傳遞消息的那個,但只要您嘗試測試的actor是可重入的 ,這應該不是問題。

我認為復雜性取決於幾個因素......

  1. 演員是多么有狀態?

如果它的行為類似於冪等函數,只是異步,那么它應該是一個簡單的事情,即模擬發送消息的actor,然后檢查它是否收到了預期的消息。 您可能希望在模擬actor上使用react / receiveWithin,以防在合理的時間段內出現響應而您可能會失敗而不是掛起。

但是,如果消息不是彼此獨立的,那么您應該使用各種消息序列和預期結果對其進行測試。

  1. 被測試的演員將與多少演員互動?

如果期望演員與許多其他演員互動,並且它是有狀態的,則應該與幾個演員發送/接收消息進行測試。 由於您可能無法保證消息的到達順序,因此您應確保置換演員發送消息的順序,或者在演員生成消息時引入隨機暫停並多次運行測試。

我不知道有任何用於測試演員的預構建框架,但你可能會想到Erlang的靈感。

http://svn.process-one.net/contribs/trunk/eunit/doc/overview-summary.html

我一直想知道如何自己測試演員。

以下是我提出的問題,是否有人看到這種方法存在問題?

而不是直接發送消息,如果您的actor委托發送給函數的消息怎么辦?

然后,您的測試可以將該函數替換為跟蹤調用次數和/或調用該方法的參數的函數:

class MyActor extends Actor {

  var sendMessage:(Actor, ContactMsg) => Unit = {
    (contactActor, msg) => {
      Log.trace("real sendMessage called")
      contactActor ! msg 
    }
  }

  var reactImpl:PartialFunction(Any, Unit) = {
      case INCOMING(otherActor1, otherActor2, args) => {

        /* logic to test */
        if(args){
          sendMessage(otherActor1, OUTGOING_1("foo"))

        } else {
          sendMessage(otherActor2, OUTGOING_2("bar"))
        }
      }
  }

  final def act = loop {
    react {
      reactImpl
    }
  }

您的測試用例可能包含以下代碼:

// setup the test
var myActor = new MyActor
var target1 = new MyActor
var target2 = new MyActor
var sendMessageCalls:List[(Actor, String)] = Nil

/*
* Create a fake implementation of sendMessage
* that tracks the arguments it was called with
* in the sendMessageCalls list:
*/
myActor.sendMessage = (actor, message) => {
  Log.trace("fake sendMessage called")
  message match {
    case OUTGOING_1(payload) => { 
      sendMessageCalls = (actor, payload) :: sendMessageCalls
    }
    case _ => { fail("Unexpected Message sent:"+message) }
  }
}

// run the test
myActor.start
myActor.reactImpl(Incoming(target1, target2, true))

// assert the results
assertEquals(1, sendMessageCalls.size)
val(sentActor, sentPayload) = sendMessageCalls(0)
assertSame(target1, sentActor)
assertEquals("foo", sentPayload)
// .. etc.

我試圖對一個演員進行單元測試(它有效)。 我正在使用Specs作為框架。

object ControllerSpec extends Specification {
  "ChatController" should{
    "add a listener and respond SendFriends" in{
        var res = false
        val a = actor{}
        val mos = {ChatController !? AddListener(a)}
        mos match{
             case SendFriends => res = true
             case _ => res = false
        }
        res must beTrue
    }

這是如何工作的,通過向單例ChatController發送同步調用。 ChatController通過使用reply()進行響應 響應作為被調用函數的返回發送,並存儲到mos中。 然后匹配應用於mos獲取從ChatController發送的案例類。 如果結果是預期的(SendFriends),則將res設置為true。 res必須是True斷言決定測試的成敗。

我正在測試的演員單身人士

import ldc.socialirc.model._

import scala.collection.mutable.{HashMap, HashSet}
import scala.actors.Actor
import scala.actors.Actor._

import net.liftweb.util.Helpers._

//Message types
case class AddListener(listener: Actor)
case class RemoveListener(listener: Actor)
case class SendFriends
//Data Types
case class Authority(usr: Actor, role: String)
case class Channel(channelName: String, password: String, creator: String, motd:   String, users: HashSet[Authority])

object ChatController extends Actor {
    // The Channel List  - Shows what actors are in each Chan
    val chanList = new HashMap[String, Channel]
    // The Actor List - Shows what channels its in
    val actorList = new HashMap[Actor, HashSet[String]]

    def notifyListeners = {

    }

    def act = {
        loop {
            react {
                case AddListener(listener: Actor)=>
                    actorList += listener -> new HashSet[String]
                    reply(SendFriends)

            }
        }
    }
    start //Dont forget to start
}

雖然它不完整但它會按預期返回Sendfriends案例類。

最近, Akka增加了Actors單元測試套件。 您可以在博文中找到一些信息和代碼段。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM