I have a Scala unit test for Akka Akka. The actor is designed to poll the remote system and update the local cache. Part of the actorโs design is that he doesnโt try to poll while he is still processing or awaiting the result of the last poll in order to avoid flooding the remote system when he is experiencing slowdown.
I have a test case (shown below) that uses Mockito to simulate a slow network call and checks that when the actor is informed about the update, he will not make another network call until the current one is completed. He verifies that the actor did not make another call, checking for lack of interaction with the remote service.
I want to remove the call to Thread.sleep . I want to test the actorโs functionality, not relying on the expectation of hard time, in every test run, which is fragile, and wastes time. The test can interrogate or block, waiting for the condition, with a timeout. This will be more reliable and will not lose time when the test passes. I also have an added restriction that I want to maintain the state used to prevent the var allowPoll from limiting the number of polls PollingActor .
- Is there a way to keep waiting until the actor completes the messaging itself? If there is a way, I can wait until this before trying to argue.
- Do I need to send an internal message? Can I maintain internal state with a streaming data structure like
java.util.concurrent.AtomicBoolean . I did this, and this code seems to work, but I'm not knowledgeable enough about Akka to see if she was discouraged - a colleague recommended a self-help style. - Are there more efficient features with the same semantics? Then I would choose the integration test instead of unit test, although I'm not sure if it will solve this problem.
The current actor looks something like this:
class PollingActor(val remoteService: RemoteServiceThingy) extends ActWhenActiveActor { private var allowPoll: Boolean = true def receive = { case PreventFurtherPolling => { allowPoll = false } case AllowFurtherPolling => { allowPoll = true } case UpdateLocalCache => { if (allowPoll) { self ! PreventFurtherPolling remoteService.makeNetworkCall.onComplete { result => { self ! AllowFurtherPolling
And the unit test, in specs2, looks like this:
"when request has finished a new requests can be made" ! { val remoteService = mock[RemoteServiceThingy] val actor = TestActorRef(new PollingActor(remoteService)) val slowRequest = new DefaultPromise[String]() remoteService.makeNetworkCall returns slowRequest actor.receive(UpdateLocalCache) actor.receive(UpdateLocalCache) slowRequest.complete(Left(new Exception)) // Although the test calls the actor synchronously, the actor calls *itself* asynchronously, so we must wait. Thread.sleep(1000) actor.receive(UpdateLocalCache) there was two(remoteService).makeNetworkCall }
source share