0

In my TestKit test

"A History Actor" must {

    // given
    val historyActorRef = TestActorRef(new HistoryActor("history-file.log"))       // Creation of the TestActorRef
    val writerActorRef = TestActorRef(new WriterActor("history-file.log"))       // Creation of the TestActorRef

    historyActorRef.underlyingActor.writerActor = writerActorRef

    "receive messages and change state" in {  // integration-like test

      // This call is synchronous. The actor receive() method will be called in the current thread

      // when
      historyActorRef ! WriteMsg("line 1")

      // then (1) - got WriteResult (from WriterActor as result of getting WriteMsg)
      within(200 millis) {
        expectMsg(WriteResult(1, 7))
      }

      // then (2) - state
      historyActorRef.underlyingActor.lastWrite must equal(WriteResult(1,7)) // With actorRef.underlyingActor, we can access the react actor instance created by Akka
    }
  }

This test fails, because it is still WriteResult(0,0)

The way in works in my HistoryActor:

   case cmd: WriteMsg => {

      log.info("forwarding " + cmd + " to the writer" )

      writerActor ! cmd

    }

    case result: WriteResult => {

      log.info("WriteResult: " + result)

      lastWrite = result                  // update the state

    } 

So, how to make test to make sure that WriteResult has already handled when we check for result?

P.S. I guess I should have considered to test WriterActor separately, but let's say I want that integration-like test.

ses
  • 13,174
  • 31
  • 123
  • 226
  • I see two assertions in the test from above. Which of the two is not passing now that you are using `TestActorRef`. Also, is `writeActorRef` really supposed to be instantiated as a new instance of the `HistoryActor` or is this a typo? – cmbaxter Jul 08 '15 at 18:00
  • typo. fixed. it fails on " expectMsg(WriteResult(1, 7))" never reach it- assertion failed: timeout. guess I will share the git project – ses Jul 08 '15 at 19:43
  • I can see why that never happens. Without seeing the code for the write actor, I'm guessing it sends a `WriteResult` back to `sender()` which will be the history actor. The history actor receives that and updates its internal state, but does not send a message back to the `sender()` that sent it the original `WriteMsg`. If the original sender of the initial `WriteMsg` is never to receive a response and all that is to happen is the internal state is to be updated then just remove that assertion. – cmbaxter Jul 08 '15 at 19:50
  • What you are saying when you say `expectMsg` is that the test itself (the implicit sender brought in by `TestKit`) is receiving a response message from the message it initially sent in to kick off the test. I don't think that is what you are trying to assert thus the suggestion to remove it. I think you are trying to say that the write actor received that message but that's not how the test kit assertions work. Simply verifying that the internal state is updated should be sufficient. – cmbaxter Jul 08 '15 at 19:53
  • while reading you replies: https://github.com/Sergey80/akka-play-ws-scala-sample/blob/master/test/ActorsTest.scala – ses Jul 08 '15 at 19:55
  • yep. thanks. still figuring out how all this works together. – ses Jul 08 '15 at 19:59

1 Answers1

1

You need to wrap both actors under test here in TestActorRefs if you are not already doing that. That will ensure that both use the calling thread dispatcher to take the asynchronicity out of your test scenario. You can also consider replacing your writeActor with a TestProbe for your test and then just mock out it's behavior.

Update

Per my comments:

What you are saying when you say expectMsg is that the test itself (the implicit sender brought in by TestKit) is receiving a response message from the message it initially sent in to kick off the test. I don't think that is what you are trying to assert thus I suggest you remove it. I think you are trying to say that the write actor received that message but that's not how the test kit assertions work. Simply verifying that the internal state is updated should be sufficient

cmbaxter
  • 35,283
  • 4
  • 86
  • 95
  • @ses, why don't you share more of your test code in your original post so I can see if it looks correct to me with usage of `TestActorRef`. – cmbaxter Jul 08 '15 at 17:40