How to test an actor with different configuration?

Hi all

I’ve written test for actor as follows:

class DetectorSpec extends AsyncFeatureSpec with Matchers
  with GivenWhenThen
  with BeforeAndAfter
  with BeforeAndAfterAll
  with ParallelTestExecution {

  implicit val ec = ExecutionContext.global

  private val sap = new SapMock()
    .withExposedPorts(8080)
    .waitingFor(Wait.forHttp("/"))

  private val kafka = new KafkaContainer()

  sap.start()
  kafka.start()

  override def afterAll() {
    sap.stop()
    kafka.stop()
  }

  def withKafkaAndSapOnline(testCode: (TestProbe, ActorRef) => Future[Assertion]): Future[Assertion] = {

    val config = ConfigFactory.parseString(
      s"""
         kafka {
           servers = "${kafka.getBootstrapServers}"
         }
         sap {
           server = "ws://${sap.getContainerIpAddress}:${sap.getMappedPort(8080)}"
         }""")

    val system = ActorSystem("testSystem", config)
    val listener = TestProbe()(system)
    val detector = system.actorOf(DetectorSupervisor.props)
    complete {
      testCode(listener, detector)
    } lastly {
      //Await.ready(system.terminate(), 1.second)
    }

  }


  def withKafkaAndSapOffline(testCode: (TestProbe, TestProbe, ActorRef) => Future[Assertion]): Future[Assertion] = {

    val config = ConfigFactory.parseString(
      s"""
         kafka {
           servers = "127.0.0.1:9092"
         }
         sap {
           server = "ws://127.0.0.1"
         }""")

    val system = ActorSystem("testSystem", config)
    val listener1 = TestProbe()(system)
    val listener2 = TestProbe()(system)
    val detector = system.actorOf(DetectorSupervisor.props)
    complete {
      testCode(listener1, listener2, detector)
    } lastly {
      //Await.ready(system.terminate(), 1.second)
    }

  }

  def withKafkaOfflineSapOnline(testCode: (TestProbe, ActorRef) => Future[Assertion]): Future[Assertion] = {

    val config = ConfigFactory.parseString(
      s"""
         kafka {
           servers = "127.0.0.1:9092"
         }
         sap {
           server = "ws://${sap.getContainerIpAddress}:${sap.getMappedPort(8080)}"
         }""")

    val system = ActorSystem("testSystem", config)
    val listener = TestProbe()(system)
    val detector = system.actorOf(DetectorSupervisor.props)

    complete {
      testCode(listener, detector)
    } lastly {
      //Await.ready(system.terminate(), 1.second)
    }
  }

  def withKafkaOnlineSapOffline(testCode: (TestProbe, ActorRef) => Future[Assertion]): Future[Assertion] = {

    val config = ConfigFactory.parseString(
      s"""
         kafka {
           servers = "${kafka.getBootstrapServers}"
         }
         sap {
           server = "ws://127.0.0.1:8080"
         }""")

    val system = ActorSystem("testSystem", config)
    val listener = TestProbe()(system)
    val detector = system.actorOf(DetectorSupervisor.props)

    complete {
      testCode(listener, detector)
    } lastly {
      //Await.ready(system.terminate(), 1.second)
    }
  }


  feature("Detect Kafka and SAP availability") {
    info("As a technical user, I want to be notified in real time, if Kafka and SAP is up and running or not.")
    scenario("SAP and Kafka are available") {
      withKafkaAndSapOnline { (listener, detector) =>
        Given("I am waiting for the current state message")
        detector ! AddNewListener(listener.ref)
        When("I am receive the state message")
        val res = listener.expectMsgPF[Assertion](10.second) _
        Then("it should contain `SAP and Kafka are online`")
        res {
          case status: ServerStatus =>
            status.health should be(ServersOnline)
        }
      }
    }

    scenario("SAP is online and Kafka is offline") {
      withKafkaOfflineSapOnline { (listener, detector) =>
        Given("I am waiting for the current state message")
        detector ! AddNewListener(listener.ref)
        When("I am receive the state message")
        val res = listener.expectMsgPF[Assertion](10.second) _
        Then("it should contain `Kafka is offline`")
        res {
          case status: ServerStatus =>
            status.health should be(ServersOffline)
        }
      }
    }

    scenario("SAP is offline and Kafka is online") {
      withKafkaOnlineSapOffline { (listener, detector) =>
        Given("I am waiting for the current state message")
        detector ! AddNewListener(listener.ref)
        When("I am receive the state message")
        val res = listener.expectMsgPF[Assertion](10.second) _
        Then("it should contain `SAP is offline`")
        res {
          case status: ServerStatus =>
            status.health should be(ServersOffline)
        }
      }
    }

    scenario("SAP and Kafka are offline") {
      withKafkaAndSapOffline { (listener1, listener2, detector) =>
        Given("I am registering two listeners")
        detector ! AddNewListener(listener1.ref)
        detector ! AddNewListener(listener2.ref)
        When("I am receive the state message")
        val res1 = listener1.expectMsgPF[Assertion](10.second) _
        val res2 = listener2.expectMsgPF[Assertion](10.second) _
        Then("it should contain `Kafka and SAP are offline`")
        res1 {
          case status: ServerStatus =>
            status.health should be(ServersOffline)
        }
        res2 {
          case status: ServerStatus =>
            status.health should be(ServersOffline)
        }
      }
    }
  }
}

The test is working as expected, but if is it the right way to test the actor like this?
I’ve created for every test a new ActorSystem, because each test needs different configuration.
Do I test the actor in the right way?
I read on the AKKA doc, that creating several ActorSystem on one JVM should be avoided.
But for the testing purpose, it should be fine or not?

Thanks

In tests you can create many ActorSystems like that, but make sure to terminate them.

1 Like

How to terminate it correctly?

actorSystem.terminate() followed by Await on the returned Future. You can also use TestKit.shutdown(actorSystem)

1 Like