Подтвердить что ты не робот

Единичное тестирование scala участников

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

4b9b3361

Ответ 1

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

Ответ 2

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

  • Как проявляется актерский статус?

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

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

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

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

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

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

Ответ 3

Мне интересно, как тестировать самих Актеров.

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

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

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

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.

Ответ 4

Моя попытка установки тестирования актера (работает). Я использую 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
    }

Как это работает, отправляя синхронный вызов singleton ChatController. ChatController отвечает с помощью ответа(). Ответ отправляется как возврат вызываемой функции, которая сохраняется в mos. Затем для mos получает класс соответствия, который был отправлен из ChatController. Если результатом является то, что ожидается (SendFriends), установите res на true. Res должно быть истинным. Утверждение определяет успех или неудачу теста.

Мой актер singleton, который я тестирую

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
}

Несмотря на то, что он не завершен, он возвращает класс класса "Подруги", как и ожидалось.

Ответ 5

Сюита для модульного тестирования Актеров недавно была добавлена ​​в Akka. Вы можете найти информацию и фрагменты кода в this blogpost.