Юнит-тестирование актеров скала - PullRequest
12 голосов
/ 23 января 2009

Кто-нибудь знает хороший способ юнит-тестирования актеров Scala? В общем смысле у меня есть актер, который получает сообщение и отправляет другие сообщения в ответ. Это делается в нескольких потоках, и неправильный субъект может либо отправлять неправильные сообщения, либо вообще не отправлять сообщения. Мне нужен простой способ создания актера-макета, который отправляет и получает сообщения для тестируемого актера. Есть ли опыт в этой области?

Ответы [ 5 ]

5 голосов
/ 24 января 2009

Из-за динамической природы передачи сообщений в стиле актера, насмешливые актеры обычно не представляют никаких проблем. Просто создайте актера, который получает желаемое сообщение, и вы свободны дома. Вам, конечно же, нужно убедиться, что этот фиктивный актер является тем, которому передаются сообщения, но это не должно быть проблемой, если актер, которого вы пытаетесь проверить, reentrant .

3 голосов
/ 24 января 2009

Я думаю, что сложность зависит от пары факторов ...

  1. Насколько полон актер?

Если она ведет себя как идемпотентная функция, только асинхронная, тогда нужно просто смоделировать актера, который отправляет сообщение и затем проверяет, что он получил ожидаемые сообщения обратно. Возможно, вы захотите использовать ответную реакцию на получение актера в случае, если есть ответ в течение разумного периода времени, который вы можете потерпеть неудачу, а не зависнуть.

Однако, если сообщения не зависят друг от друга, вам следует проверить их с различными последовательностями сообщений и ожидаемыми результатами.

  1. Сколько актеров будет взаимодействовать с испытуемым?

Если ожидается, что актер взаимодействует со многими другими, и он с состоянием, то его следует протестировать с несколькими субъектами, отправляющими / получающими сообщения. Поскольку у вас, вероятно, нет никакой гарантии порядка, в котором будут поступать сообщения, вы должны убедиться, что вы либо изменили порядок, в котором акторы отправляют сообщения, либо вставили случайные паузы в акторах, генерирующих сообщения, и многократно запускали тест.

Мне неизвестны какие-либо готовые фреймворки для тестирования актеров, но вы, возможно, можете обратиться к Эрлангу за вдохновением.

http://svn.process -one.net / вклад / багажник / eunit / док / обзор-summary.html

1 голос
/ 05 ноября 2009

Моя попытка юнит-тестирования актера (работает). Я использую 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. Затем применяется сопоставление для получения класса дел, который был отправлен из ChatController. Если результат соответствует ожидаемому (SendFriends), установите для res значение true. res должно быть верно утверждение определяет успех или неудачу теста.

Мой актерский синглтон, который я тестирую

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, как и ожидалось.

1 голос
/ 14 июля 2009

Я задавался вопросом, как самому проверить актеров.

Вот что я придумал, кто-нибудь видит проблемы с таким подходом?

Вместо того, чтобы отправлять сообщения напрямую, что если ваш актер делегировал отправку сообщения в функцию?

Тогда ваши тесты могут поменять функцию на ту, которая отслеживает число вызванных раз и / или аргументы, с которыми вызывался метод:

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.
0 голосов
/ 13 февраля 2011

Пакет для юнит-тестирования Актеров был недавно добавлен в Akka . Вы можете найти некоторую информацию и фрагменты кода в этом блоге.

...