Let's say I have an actor like this (Using Akka 2.1 with Scala 2.10):
class ClientActor extends Actor with ActorLogging {
val configurationManager = context.actorOf(Props[ConfigurationManager], "ConfigurationManager")
def disconnected: Receive = {
case msg: Connect =>
configurationManager ! msg
context.become(connecting)
}
..
def recieve = disconnected
}
So now when the Client receives a Connect message, it sends it to the ConfigurationManager and also goes into a different state. That's fine, but now I want to test this.
val clientRef = TestActorRef(new ClientActor).
clientRef ! new Connect
// ??
I can't expectMsg() or so here since it will be sent to a different actor. What is the best practice to handle such a situation? I just want to make sure that the message gets sent, but I dont know how to do this.
Thanks,
Michael
Pass the dependency in as a constructor parameter:
Normal code:
val configActor =
system.actorOf(Props[ConfigurationManager], "configManager")
val clientActor =
system.actorOf(Props(new ClientActor(configActor)), "clientActor")
Test code:
val clientActor =
system.actorOf(Props(new ClientActor(testActor)), "clientActor")
Perhaps you should just trust that the message sending mechanisms inside Akka, work as advertised. If you really, really can't trust this, then the best solution is to download the Akka source code and either add your own unit tests to cover your use cases, or modify the code to support your own unit testing needs.
Or you could use something like Camel to do all the message sending and intercept messages that way.
If you abstract out the creation of the collaborating actor, then you can inject a test actor that does whatever you want. The situation is very similar to testing collaboration between ordinary objects.
Related
What does Akka's Inbox.create(actorsystem) actually do? Will it create a new mailbox for all the actors as we have created the inbox on the system? And what does inbox.watch(actorref) do?
Can you explain what inbox.send and inbox.receive actually do?
From the source code for Inbox:
/**
* An Inbox is an actor-like object which is interrogated from the outside.
* It contains an actor whose reference can be passed to other actors as
* usual and it can watch other actors’ lifecycle.
*/
The Inbox object is a way to communicate with an actor from outside an actor. Let's say we wanted to send messages to and receive replies from an actor named myActor, and we wanted to do this from outside an actor. (The below code samples are adapted from the documentation.)
// this code is not inside an actor
ActorRef myActor = ???
final Inbox inbox = Inbox.create(system);
inbox.send(myActor, "ping");
Inbox.create(system) creates a system-level actor under the covers. inbox.send(myActor, "ping"); sends the message "ping" to myActor with Inbox's internal actor as the sender. Because the Inbox's actor is the sender, it can get a reply from myActor with inbox.receive:
try {
assert inbox.receive(Duration.create(1, TimeUnit.SECONDS)).equals("pong");
} catch (java.util.concurrent.TimeoutException e) {
// timeout
}
inbox.watch registers the Inbox's actor to be notified via DeathWatch when myActor has been terminated:
inbox.watch(myActor);
myActor.tell(PoisonPill.getInstance(), ActorRef.noSender());
try {
assert inbox.receive(Duration.create(1, TimeUnit.SECONDS)) instanceof Terminated;
} catch (java.util.concurrent.TimeoutException e) {
// timeout
}
Inbox.create(system) does not create a new mailbox for all the actors in a system. Don't let the word "inbox" confuse you. Also, Akka enables by default a dispatcher that creates one mailbox per actor; the Inbox object doesn't change that.
I want to unit test a module by throwing messages at it via Event Aggregation to make sure it responds appropriately, either by setting properties appropriately, or by publishing other messages as a result. I am using Prism 6.
In my project, the infrastructure project has:
public class ImportantMessage : PubSubEvent<string>
{
}
ModuleA publishes a message like this:
eventAggregator.GetEvent<ImportantMessage>().Publish(importantString);
ModuleB receives the message like this:
eventAggregator.GetEvent<ImportantMessage>().Subscribe(HandleImportantMessage);
Here is HandleImportantMessage:
public void HandleImportantMessage(string importantString)
{
. . .
}
The ModuleB constructor is called as follows:
ModuleB(IEventAggregator EventAggregator)
This constructor is called by the Prism framework. For unit testing, I need to create an instance of ModuleB, and pass an IEventAggregator, probably a fake one created by Moq. And I want to do this in such a way that the message I publish carries importantString with it.
If I Google the phrase “unit tests with moq and event aggregation,” there are
several references, but I didn’t see how to use any of these approaches to pass “importantString” from ModuleA To ModuleB. The sample code for Prism 5 creates a fake event aggregator, but without using Moq. I don't understand how it works, and don't see how to pass a string with it.
My test code starts off something like this:
var moqEventAggregator = new Mock(IEventAggregator);
var moqImportantMessage = new Mock<ImportantMessage>();
moqEventAggregator.Setup(x => x.GetEvent<ImportantMessage>());
Some of the references I have seen apply something like .Returns(eventBeingListenedTo.Object);
to moqEventAggregator after Setup is applied.
I obviously need to apply .Setup(something) to moqImportantMessage in order to pass importantString, but I don't see exactly what yet.
What am I missing? How do I pass a string with the fake published message?
Basically you need to mock 2 things here:
The event aggregator
The event itself
Given you have the mock of the event you need to do as you said:
moqEventAggregator.Setup(x => x.GetEvent<ImportantMessage>()).Returns(moqImportantMessage);
Mocking the event itself should be like so:
Action<string> action;
moqImportantMessage.Setup(_ => _.Subscribe(It.IsAny<Action<string>>>()))
.Callback(_action =>
{
action = _action;
});
And then you can raise the subscription like so:
action("some string");
I've started writing unit tests for new actor with state. The state is initialised in the OnActivateAsync method which is called by Service Fabric when the Actor is activated.
When unit testing, I'm creating the Actor myself and as the method is protected I don't have access from my unit test to call this method myself.
I'm wondering on the usual approach for this kind of testing. I could mock the Actor and mock the state, but for the code I want to test call the original. Am wondering if there is another approach I've not come across.
Another approach would be to move the State initialisation to somewhere else like a public method or in the constructor but the template for an Actor has the code there so it may be a best practice.
Use the latest version of ServiceFabric.Mocks NuGet package. It contains special extension to invoke OnActivateAsync protected method and the whole tool set for ServiceFabric unit testing.
var svc = MockActorServiceFactory.CreateActorServiceForActor<MyActor>();
var actor = svc.Activate(new ActorId(Guid.NewGuid()));
actor.InvokeOnActivateAsync().Wait();
I like to use the InternalsVisibleTo attribute and an internal method on the actor, which calls the OnActivateAsync method.
In the target Actor project, AssemblyInfo.cs add a line like this:
[assembly: InternalsVisibleTo("MyActor.Test")]
Where "MyActor.Test" is the name of the test project you want to grant access to your internal members.
In the target Actor class add a method something like this:
internal Task InvokeOnActivateAsync()
{
return OnActivateAsync();
}
This way you can invoke the OnActivateAsync method from your test project something like this:
var actor = CreateNewActor(id);
actor.InvokeOnActivateAsync()
I appreciate this is not ideal, but you can use reflection to call the OnActivateAsync() method.
For example,
var method = typeof(ActorBase).GetMethod("OnActivateAsync", BindingFlags.Instance | BindingFlags.NonPublic);
await (Task)method.Invoke(actor, null);
This way you'll be testing the actual method you want to test and also won't be exposing methods you don't really want to expose.
You may find it useful to group the creation of the actor and the manual call to OnActivateAsync() in a single method so that it's used across your test suite and it mimics the original Service Fabric behaviour.
From: https://www.chrisstucchio.com/blog/2013/actors_vs_futures.html
suggests that this is safe:
class FooCounter extends Actor {
var count: Long = 0
def receive = {
case Foo => { count += 1}
case FooCountRequest => { sender ! count }
}
}
Isn't it possible that there will be multiple simultaneous calls to receive, making the value of count uncertain.
My understanding is that the only way this could ever be safe would be if the receive call on this object was made mutex with itself.
The receive method is never called simultaneously by multiple threads. Messages residing in an Actor's mailbox are processed one-at-a-time by the receive method. Multiple other Actors, or functions outside of the ActorSystem, can concurrently enqueue messages to the Actor's mailbox but the ActorSystem eventually orders the messages. From the docs:
Enqueuing happens in the time-order of send operations, which means
that messages sent from different actors may not have a defined order
at runtime due to the apparent randomness of distributing actors
across threads.
The receive method's serial processing is guaranteed by the fact that you never actually get an Actor value (which has a receive) from the ActorSystem. Rather, you only get an ActorRef which does not have receive method:
val actorSystem = akka.actor.ActorSystem()
//not an Actor but an ActorRef
val actorRef : ActorRef = actorSystem actorOf Props[FooCounter]
actorRef.receive(Foo) //COMPILE TIME ERROR!
The only way to "invoke" the receive method is to send a message to the ActorRef:
actorRef ! Foo //non-blocking, enqueues a Foo object in the mailbox
Relating back to your question: the ActorSystem acts as a pseudo-mutex for all Actor instances.
Therefore, the code in your example is absolutely safe and the state will only be accessed by one message at any given time.
Totally agree with Ramon. You can think of it have a mail box outside your house(Actor) and mail are coming to your mail box though your address (ActorRef) and you only have 1 single person at your home to take care your mail one at a time.
Besides, for more functional style and maintain immutability of code. I would do the following instead:
class FooCounter extends Actor {
def _receive(count: Long): Receive = {
case Foo =>
context.become(_receive(count + 1))
case FooCountRequest =>
sender() ! count
}
def receive = _receive(0L)
}
For this simple example, there are no difference between mine and yours. But when system become more complex, my code are less error prone.
I have a Scala unit test for an Akka actor. The actor is designed to poll a remote system and update a local cache. Part of the actor's design is that it doesn't attempt to poll while it's still processing or awaiting the result of the last poll, to avoid flooding the remote system when it experiences a slowdown.
I have a test case (shown below) which uses Mockito to simulate a slow network call, and checks that when the actor is told to update, it won't make another network call until the current one is complete. It checks the actor has not made another call by verifying a lack of interactions with the remote service.
I want to eliminate the call to Thread.sleep. I want to test the functionality of the actor without relying on waiting for a hardcoded time, in every test run, which is brittle, and wastes time. The test can poll or block, waiting for a condition, with a timeout. This will be more robust, and will not waste time when the test is passing. I also have the added constraint that I want to keep the state used to prevent extra polling var allowPoll limited in scope, to the internals of the PollingActor.
is there a way force a wait until the actor is finished messaging itself? If there's a way I can wait until then before trying to assert.
is it necessary to send the internal message at all? Couldn't I maintain the internal state with a threadsafe datastructure, such as java.util.concurrent.AtomicBoolean. I have done this and the code appears to work, but I'm not knowledgeable enough about Akka to know if it's discouraged -- a colleague recommended the self message style.
is there better, out-of-the-box functionality with the same semantics? Then I would opt for an integration test instead of a unit test, though I'm not sure if it would 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
// process result
}
}
}
}
}
}
trait RemoteServiceThingy {
def makeNetworkCall: Future[String]
}
private case object PreventFurtherPolling
private case object AllowFurtherPolling
case object UpdateLocalCache
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
}
The way we have chosen to solve this for now is to inject the equivalent of an observer into the actor (piggybacking on an existing logger which wasn't included in the listing in the question). The actor can then tell the observer when it has transitioned from various states. In the test code we perform an action then wait for the relevant notification from the actor, before continuing and making assertions.
In the test we have something like this:
actor.receive(UpdateLocalCache)
observer.doActionThenWaitForEvent(
{ actor.receive(UpdateLocalCache) }, // run this action
"IgnoredUpdateLocalCache" // then wait for the actor to emit an event
}
// assert on number of calls to remote service
I don't know if there's a more idiomatic way, this seems like a reasonable suggestion to me.