title: Testing Akka Typed behavior
body: <p>How would I test that a given behavior sends the messages I expect?</p>
  
  <p>Say, three messages of some type, one after the other... </p>
  
  <p>With regular actors (untyped) there was the TestProbe from regular Akka with methods like <code>expectedMsg</code>:</p>
  
  <p><a href="http://doc.akka.io/api/akka/current/index.html#akka.testkit.TestProbe" rel="nofollow">http://doc.akka.io/api/akka/current/index.html#akka.testkit.TestProbe</a></p>
  
  <p>With akka-typed I'm scratching my head still. There is something called <a href="http://doc.akka.io/api/akka/2.4.0/index.html#akka.typed.EffectfulActorContext" rel="nofollow">EffectfulActorContext</a>, but I've no idea how to use that.</p>
  
  <h1>Example</h1>
  
  <p>Say I am writing a simple <code>PingPong</code> service, that given a number <code>n</code> replies with <code>Pong(n)</code> <code>n</code>-times. So:</p>
  
  <pre><code>-&gt; Ping(2)
  Pong(2)
  Pong(2)
  -&gt; Ping(0)
  # nothing
  -&gt; Ping(1)
  Pong(1)
  </code></pre>
  
  <p>Here is how this behavior might look:</p>
  
  <pre><code>case class Ping(i: Int, replyTo: ActorRef[Pong])
  case class Pong(i: Int)
  
  val pingPong: Behavior[Ping] = {
      Static {
        case Ping(i, replyTo) =&gt; (0 until i.max(0)).map(_=&gt; replyTo ! Pong(i))
      }
    }
  </code></pre>
  
  <h1>My Hack</h1>
  
  <p>Now since I can't figure out how to make this work, the "hack" that I am doing right now is making the actor <em>always</em> reply with a list of responses. So the behavior is:</p>
  
  <pre><code>case class Ping(i: Int, replyTo: ActorRef[List[Pong]])
    case class Pong(i: Int)
  
    val pingPong: Behavior[Ping] = {
      Static {
        case Ping(i, replyTo) =&gt; replyTo ! (0 until i.max(0)).map(_=&gt;Pong(i)).toList
      }
    }
  </code></pre>
  
  <p>Given this <em>hacky</em> change, the tester is easy to write:</p>
  
  <pre><code>package com.test
  
  import akka.typed.AskPattern._
  import akka.typed.ScalaDSL._
  import akka.typed.{ActorRef, ActorSystem, Behavior, Props}
  import akka.util.Timeout
  import com.test.PingPong.{Ping, Pong}
  import org.scalatest.{FlatSpec, Matchers}
  
  import scala.concurrent.ExecutionContext.Implicits.global
  import scala.concurrent.duration._
  import scala.concurrent.{Await, Future}
  
  object PingPongTester {
    /* Expect that the given messages arrived in order */
    def expectMsgs(i: Int, msgs: List[Pong]) = {
      implicit val timeout: Timeout = 5 seconds
      val pingPongBe: ActorSystem[Ping] = ActorSystem("pingPongTester", Props(PingPong.pingPong))
  
      val futures: Future[List[Pong]] = pingPongBe ? (Ping(i, _))
      for {
        pongs &lt;- futures
        done &lt;- {
          for ((actual, expected) &lt;- pongs.zip(msgs)) {
            assert(actual == expected, s"Expected $expected, but received $actual")
          }
          assert(pongs.size == msgs.size, s"Expected ${msgs.size} messages, but received ${pongs.size}")
          pingPongBe.terminate
        }
      } Await.ready(pingPongBe.whenTerminated, 5 seconds)
    }
  }
  
  
  object PingPong {
    case class Ping(i: Int, replyTo: ActorRef[List[Pong]])
    case class Pong(i: Int)
  
    val pingPong: Behavior[Ping] = {
      Static {
        case Ping(i, replyTo) =&gt; replyTo ! (0 until i.max(0)).map(_=&gt;Pong(i)).toList
      }
    }
  }
  
  class MainSpec extends FlatSpec with Matchers {
    "PingPong" should "reply with empty when Pinged with zero" in {
      PingPongTester.expectMsgs(0, List.empty)
    }
    it should "reply once when Pinged with one" in {
      PingPongTester.expectMsgs(1, List(Pong(1)))
    }
    it should "reply with empty when Pinged with negative" in {
      PingPongTester.expectMsgs(-1, List.empty)
    }
    it should "reply with as many pongs as Ping requested" in {
      PingPongTester.expectMsgs(5, List(Pong(5), Pong(5), Pong(5), Pong(5), Pong(5)))
    }
  }
  </code></pre>