Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I unit test an akka Actor synchronously?

I've got an actor that will write a file after receiving a certain number of messages.

When compiling, Maven runs all the unit tests we have defined. The problem is that the unit test to check that the file was successfully written to disk happens before the Actor writes the file (which it does correctly).

I've found some documentation for testing Actors, but they're all out of date by several years. How can I wait for a bit before checking that the file exists?

like image 984
CPS Avatar asked Jan 03 '14 18:01

CPS


People also ask

Is Akka asynchronous?

Akka actors are asynchronous from the beginning. Reactive programs can be implemented in either way, synchronous and asynchronous.

Are Akka actors threads?

Akka actors use java threads internally. More than a few thousand threads running simultaneously produces overhead on most desktop machines. Akka Actors simplifies this problem by providing awake-on-demand actors who do not occupy a thread unless they have some work to do.

What is actor system in Akka?

What is an Actor in Akka? An actor is essentially nothing more than an object that receives messages and takes actions to handle them. It is decoupled from the source of the message and its only responsibility is to properly recognize the type of message it has received and take action accordingly.

What is Akka props?

Props is a configuration class which is used to specify options while creating an actor. It is immutable, so it is thread-safe and shareable. You can implement Props by importing akka.


2 Answers

Just to sum up all comments and suggestions:

  • Refactor non-actor specific code to regular classes and test it using regular means (unit tests, etc). This is more of a unit test approach.
  • Use TestActorRef to test a single actor - you can control events synchronously and rich into actor internals. Use TestKit which provides much more including "special" actor system. This is more of a behavioural test approach.
  • Use documentation here to learn more about how Akka TestKit works but in short you get control over your actor and synchronous execution.
like image 56
yǝsʞǝla Avatar answered Oct 27 '22 00:10

yǝsʞǝla


For synchronous actor testing, use TestProbes (akka.testkit) similar to this:

import org.scalatest.{FunSuite, BeforeAndAfterAll}
import org.scalatest.matchers.ShouldMatchers
import scala.concurrent.duration._
import scala.util.Random
import scala.util.control.NonFatal
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
import akka.actor.{ActorSystem, ActorRef, Actor, Props}
import akka.testkit.{TestKit, ImplicitSender, TestProbe}
import scala.concurrent._
import ExecutionContext.Implicits.global

@RunWith(classOf[JUnitRunner])
class Example extends TestKit(ActorSystem("filetest"))
  with FunSuite
  with BeforeAndAfterAll
  with ShouldMatchers
  with ImplicitSender
  with Tools {

  override def afterAll(): Unit = {
    system.shutdown()
  }

  test("Show synchronous actor test") {
    val tester = TestProbe()
    val fileActor = system.actorOf(Props(classOf[FileActor]), "case2-primary")

    tester.send(fileActor, CreateFile(1))
    tester.expectMsg(FileCreated(1)) // Will synchronously wait (~500ms in this example)
  }
}

case class CreateFile(id: Long)
case class FileCreated(id: Long)

class FileActor extends Actor {
  def receive = {
    case CreateFile(id) => {
      val s = sender
      createFile(id).map( id => s ! FileCreated(id))
    }
  }

  def createFile(id: Long): Future[Long] = future {
    // "Create" the file...
    Thread.sleep(500)
    id
  }
}
like image 45
torbinsky Avatar answered Oct 27 '22 00:10

torbinsky