Unit Testing Components that Uses an Akka Actor - scala

First of all, I am not asking how to unit test an Akka Actor. I know the techniques to do that. My problem is slightly different.
I am developing a Scala program, let's call it the client, that does not use Akka Actors. However, the program uses a library, let's call it the server, whose interface is implemented using an Akka Actor.
Then, through the ask pattern, the client interacts with the server.
// This is the client program
class Client(uri: String) {
implicit val context: ActorSystem = ActorSystem("client-actor-system")
private val mainActor = context.actorSelection(uri)
def connect: Future[SomeClass] = {
implicit val timeout: Timeout = Timeout(5 seconds)
(mainActor ? Connect()).mapTo[CreationResponse]
}
}
Now, I want to write down some unit tests for Client class. Unit testing means to test a class in isolation. Every external dependency should be mocked.
How can I mock the reference to mainActor inside Client class? How can I inject in the actor system a mock actor for mainActor?
Thanks in advance.

I would inject the mainActor actor selection into the client, and create that using Akka TestKits.
Of course, you need an ActorSelection, not an ActorRef. Some solutions for that can be found here:
Giving an ActorPath for a testProbe
Or alternatively, you could make mainActor an ActorRef by sending an Identify message to the ActorSelection.

Related

How to mock HTTP service within Akka Actor

I have an actor (actually a persistent actor) that, in response to a message (command), needs to make an HTTP call. The question now is how do I deal with this HTTP call in unit test?
Normally I would use the combination of DI and mocking to inject a mock implementation of the HTTP service while testing. But I am not sure if this is how to approach the problem in Akka? Even if this is the how to approach it in Akka, I am not sure how to go about doing the injecting and mocking in testing.
Any thoughts on this? What is the idiomatic way for testing Actors that perform IO operations (HTTP calls, writing to DB etc).
PS: I am using Akka Typed.
My personal belief is that you should avoid IO operations in Actors if at all possible (see this presentation for more details).
That being said, I’m sure there are people who would disagree and you probably shouldn’t listen to me :)
Here is how I would go about mocking it for a test.
Create a trait that represents your http call.
trait Client {
def makeHttpCall(input: Int): Future[Output]
}
(You will want to create a class of some kind that implements this trait and test it separately from your actor.)
Pass an instance of that trait into your actor using its constructor/apply method.
def apply(client: Client): Behavior[...] = {
// use your client inside of your behavior
}
In your test create a mock instance of Client and pass that in to your actor. You can mock your Client using a mocking library (ScalaMock or Mockito) or you can actually just create a test implementation of your trait with relative ease:
class TestClient extends Client {
def makeHttpCall(input: Int): Future[Output] =
Future.successful(Output(...))
}
Note: all of the names for classes and methods that I chose are just placeholders. You should, of course, choose more specific names based on the context you are working in.

Akka - Best Approach to configure an Actor that consumes a REST API service (blocking operation)

I have an Akka messaging engine that delivers millions of messages during the day, both SMS and Email. I need to introduce a new type of messaging (PushNotification) which consists in having each request consume a REST API (it will also process millions). I believe that consuming a Webservice is a blocking operation, so from what I have read I need to add a separate dispatcher for this new Actor, my questions is, does it necessarily need to be a thread-pool-executor with a fixed-pool-size as mentioned here? (See https://doc.akka.io/docs/akka-http/current/handling-blocking-operations-in-akka-http-routes.html) or is it possible to use a fork-join-executor instead? Also what is the best approach in order not to affect the current 2 types of Messaging ? (SMS and EMAIL) I mean how do I avoid to starve their thread-pool ? Currently EMAIL is using a separate Dispatcher and SMS is using the Default Dispatcher. Instead of creating a new Dispatcher for the Actor with blocking operation (calling WebService) is there any other way ? Like creating a reactive web service ?
Using a RESTful API from a web service does not have to be blocking.
An easy way to consume a RESTful API from an actor is to use Akka HTTP Client. This allows you to send an HTTP request and have the result sent back as a message to an actor using the pipeTo method.
This is a very cut-down example (lightly modified from the sample in the documentation).
import akka.http.scaladsl.Http
object RestWorker {
def props(replyTo: ActorRef): Props =
Props(new RestWorker(replyTo))
}
class RestWorker(replyTo: ActorRef) extends Actor
{
implicit val ec: ExecutionContext = context.system.dispatcher
override def preStart() = {
Http(context.system).singleRequest(HttpRequest(uri = "https://1.2.3.4/resource"))
.pipeTo(self)
}
def receive = {
case resp: HttpResponse =>
val response = ??? // Process response
replyTo ! response
self ! PoisonPill
}
}

Scaldi : Bind[T < AkkaInjectable] to TestProbe.ref

I'm trying to test an Actor A inside my Play 2.4 application with Scaldi. This actor is calling injectActorRef[B] that I want to mock with a TestKit.TestProbe.
Inside my specs2, I would like to be able to retrieve the probe for mocked B while providing the corresponding TestKit.TestProbe.ref to actor A.
I would like to do something like this :
implicit val inj = (new TestModule(){
bind[TestProbe] identifiedBy 'probeForB to TestProbe()
bind[B] to inject[TestProbe]('probeForB).ref
}).injector
inject[TestProbe]('probeForB).expectMsgType[] must ...
The issue is that the ref is an ActorRef and therefore does not match the expected Btype.
Is there a clean way to do that ?
Can we specify an ActorRef to be returned by injectActorRef[B]?
I ended up overriding the bind for Actor A.
val probeForB = TestProbe()
implicit val inj = (new Module() {
bind[A] to new A() {
override def injectB(): ActorRef = probeForB.ref
}
}).injector
As you mentioned, the issue is that inject[TestProbe]('probeForB).ref gives you an ActorRef back instead of an instance of actual actor.
If you would like to test it in a way you described, then you need define a binding of ActorRef for actor B as well. For example:
bind [BActor] toProvider new BActor
bind [ActorRef] identifiedBy 'bRef to {
implicit val system = inject [ActorSystem]
injectActorRef[BActor]
}
When you have this setup, then you can override the second binding with test probe:
bind [ActorRef] identifiedBy 'bRef to inject[TestProbe]('probeForB).ref
Please note, that this example is not direct equivalent since BActor now has a different supervisor (guardian actor, that's why we need to inject an ActorSystem here).
injectActorRef delegates an actor creation to a "context" (a parent actor or actor system) with context.actorOf. What makes it helpful is that it creates a special Props that injects new instances of BActor class when akka wants to create one. This means that scaldi does not have control over the actor lifecycle (it's pretty important, since akka itself has very sophisticated mechanisms for this), it just gives akka the knowledge how to create new instances of particular actor class.
If you are creating an actor within another actor (like you described), then the lifecycle of them both is strongly connected and managed by akka. That's the reason why in this case you can't simply override and Actor binding with an ActorRef binding for the tests.

Getting instance of class used to create an actor in Akka in test

How do I get instance of class I passed to Props when creating an actor with ActorSystem.actorOf? I need that for unit tests to get reference to some properties of the actor, so the actor is local in the same JVM as test.
I don't want to use Akka's test framework because I need the actor live, it's kind of integration tests.
The underlying instance of an Actor subclass is well and truly sealed off from you and you're not going to get at it without mucking with Akka code itself. If you look at the definition of the ActorRef you'll see that it doesn't even contain a reference to the Actor!
Similarly, you cannot instantiate Actor subclasses directly using new.
I guess the Akka designers were serious about the ActorRef / Actor firewall...
The Akka Testkit is made for integration testing. To get access to the internal state of an actor send it a message asking for it. Your actor can reply to the sender which is the TestKit's testActor.

How to start Akka Actors since 2.0?

I'm using Akka Actors and I'm trying to update my code to use the latest 2.0 milestone. The API changed somewhat, for example the creation of Actors now works via something called an ActorSystem.
Starting and stopping actors changed as well - the latter is available via the ActorSystems methods .stop(..) and .shutdown(). But I can for the life of me not figure out how to start them...
The documentation is good, but seems to be missing some important points. I feel kinda stupid to ask, but how do you start actors in your Akka 2.0 environment? If I understood correctly actors who have a 'parent' are started when this parent is started - but what about the top level actor(s)?
In Akka 2.0, there is no need for a start() method because Actors are started as soon as you instantiate them in the context of an ActorSystem (or another Actor) -- but you need to instantiate them with one of the provided methods of ActorSystem or an Actor's context.
So, for example, if you have an Actor subclass called MyClass, you could start it with:
val system = ActorSystem()
val myActor = system.actorOf(Props[MyActor])
or, if your actor took constructor arguments:
val myActor = system.actorOf(Props(new MyActor("arg1"))
or, if you were in the body of another Actor,
val myActor = context.actorOf(Props(new Actor("arg1"))
and then your actor could immediately receive messages, e.g.
myActor ! MyMessage
Even your top level actors are started immediately, as all Actors in 2.0 are automatically in a supervision hierarchy. As soon as the actor is instantiated with the ActorSystem, it's ready to receive messages.