Akka (Scala) - testing messages with paramters iwth TestKit

Viewed 38

In my app I have a CartActor managing a shopping cart and OrderManager overseeing the whole shopping process:

object CartActor {

  sealed trait Command
  case class AddItem(item: Any)        extends Command
  case class RemoveItem(item: Any)     extends Command
  case object ExpireCart               extends Command
  case object StartCheckout            extends Command
  case object ConfirmCheckoutCancelled extends Command
  case object ConfirmCheckoutClosed    extends Command
  case object GetItems                 extends Command // command made to make testing easier

  sealed trait Event
  case class CheckoutStarted(checkoutRef: ActorRef) extends Event

  def props() = Props(new CartActor())
}

object OrderManager {
  sealed trait Command
  case class AddItem(id: String)                                               extends Command
  case class RemoveItem(id: String)                                            extends Command
  case class SelectDeliveryAndPaymentMethod(delivery: String, payment: String) extends Command
  case object Buy                                                              extends Command
  case object Pay                                                              extends Command
  case class ConfirmCheckoutStarted(checkoutRef: ActorRef)                     extends Command
  case class ConfirmPaymentStarted(paymentRef: ActorRef)                       extends Command
  case object ConfirmPaymentReceived                                           extends Command

  sealed trait Ack
  case object Done extends Ack //trivial ACK
}

OrderManager receives OrderManager.ConfirmCheckoutStarted(checkoutRef: ActorRef) from CartActor. I have to write unit tests to check that. I wanted to do:

  it should "start checkout" in {
    val cart = TestActorRef[CartActor]

    cart ! AddItem("Item")
    cart ! StartCheckout
    expectMsg(OrderManager.ConfirmCheckoutStarted)
  }

But I get an error: assertion failed: expected ConfirmCheckoutStarted, found ConfirmCheckoutStarted(Actor[akka://CartTest/user/$$d/checkout#-1922766677]). I see that the problem is that there is a parameter in parantheses. How can I test this? I don't care about the actorRef inside, I just want ConfirmCheckoutStarted.

1 Answers

I don't know what message tour actor in sending back. So I created this CartActor sending the message OrderManager.ConfirmCheckoutStarted(self).

  class CartActor extends Actor {

    import CartActor._

    override def receive: PartialFunction[Any, Unit] = {
      case AddItem(item) => sender ! s"item $item added."
      case StartCheckout => sender ! OrderManager.ConfirmCheckoutStarted(self)
      case msg => println(s"I cannot understand ${msg.toString}")
    }
  }

then I am executing this test which check for the actor reference:

import akka.actor.ActorSystem
import akka.testkit.{ImplicitSender, TestActorRef, TestKit}
import org.scalatest.BeforeAndAfterAll
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpecLike

class CartActorDemoSpec extends TestKit(ActorSystem("CartActorDemoSpec"))
  with ImplicitSender
  with AnyWordSpecLike
  with Matchers
  with BeforeAndAfterAll {

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

  import CartActorDemo._

  "The ActorsIntro actor" should {
    "send back hi replay" in {
      import CartActorDemo.CartActor._
      val cart = TestActorRef[CartActor]

      val item = "MyItem"
      cart ! AddItem(item)
      expectMsg(s"item $item added.")
      cart ! StartCheckout
      expectMsg(OrderManager.ConfirmCheckoutStarted(cart))
    }
  }
}

If you have another type of message sending back on your case StartCheckout you can just change it accordingly.

Related