How to unit test Akka.Net Actor State (using Become()) - unit-testing

I have an Actor and when it recieves a StartMessage, it should change state using Become(Started). How do I unit test whether or not the Actor's state has changed to Started() ?
MyActor class
public class MyActor : ReceiveActor
{
public MyActor()
{
Receive<StartMessage>(s => {
Become(Started); // This is what I want to unit test
});
}
private void Started()
{
Console.WriteLine("Woo hoo! I'm started!");
}
}
Unit Test
[TestMethod]
public void My_actor_changes_state_to_started()
{
// Arrange
var actor = ActorOfAsTestActorRef<MyActor>(Props.Create(() => new MyActor()));
// Act
actor.Tell(new StartMessage());
// Assert
var actorsCurrentState = actor.UnderlyingActor.STATE; // <-- This doesn't work
Assert.AreEqual(Started, actorsCurrentState);
}
UPDATE
Related to the answer from tomliversidge: My reason for writing this unit test was academic but in reality, it's not a good unit test which is why you aren't able to do it as I'd hoped. From Petabridge's Unit Testing Guide:
In reality, if one actor wants to know the internal state of another actor then it must send that actor a message. I recommend you follow the same pattern in your tests and don’t abuse the TestActorRef. Stick to the messaging model in your tests that you actually use in your application.

You would normal test this by message passing. For example, what messages do you process in the Started state? I'm presuming your example has been simplified to the Console.WriteLine action inside of Started.
If you send the StartMessage and then a second message that is processed when in the Started state you can then assert on a response to this second message.
As a simple suggestion:
private void Started()
{
Receive<StartMessage>(msg => {
Sender.Tell(new AlreadyStarted());
}
}
if StartMessage is received whilst in the Started state, you can then assert on receiving an AlreadyStarted message.
For more info check out the Petabridge article https://petabridge.com/blog/how-to-unit-test-akkadotnet-actors-akka-testkit/

Related

What is a good practice to write unit-test on .net core Ihostedservice?

I have a background task initiated in .net core 2.0 startup, inherits from backgroundservice, implementing StartAsync, StopAsync and ExecuteAsync. This task is to update some data in database table periodically based on some business logic.
While I can run the backgroundtask as an application and test using logs, db check and with the help of other tools, can the unit-testing is necessary for testing the backgroundtask? If so how to register the task as a service with dependencies and trigger the start and stop methods to assert the actual vs expected? Appreciate some basic sample unit-test method on testing timer based .net core ihostedservice backgroundtask.
Here is my basic test start just for sample, but not completed yet. Having said that, this is just a thought but not the exact working test. Here is what need some help from the community. Can also add some more asserts i.e. Assert.Verify()?
[Fact]
public async void Run_background_task_success()
{
//Arrange
IServiceCollection services = new ServiceCollection();
services.AddHostedService<BackgroundManagerTask>();
var serviceProvider = services.BuildServiceProvider();
var service = serviceProvider.GetService<IHostedService>() as BackgroundManagerTask;
var isExecuted = false;
if(await service.StartAsync(CancellationToken.None))
{
isExecuted = true;
}
await Task.Delay(10000);
Assert.True(isExecuted);
await service.StopAsync(CancellationToken.None);
}
Here's how I usually do it. You mention you are going to the database to update some data, so I'm assuming you are expecting that as a dependency from BackgroundManager
[Fact]
public void BackgroundManagerUpdatingDataTest()
{
// Arrange
Mock<IDataAccess> dbMock = new Mock<IDataAccess>();
dbMock.Setup(x => x.UpdateSomethingInDB(It.IsAny<BusinessObject>())).Returns(1); // One row updated from the DML in UpdateSomethingInDB from the BusinessObject
BackgroundManager sut = new BackgroundManager(dbMock.Object); // System under test.
// Act
await sut.StartAsync(CancellationToken.None);
await Task.Delay(500); // Give the test some time to execute.
await sut.StopAsync(CancellationToken.None); // Stop the Background Service.
// Assert
dbMock.Verify(x => x.UpdateSomethingInDB(It.IsAny<BusinessObject>()), Times.Exactly(1));
}
Above, we are plainly testing the update to the database occurred by Mocking the data access call and verifying that it was called exactly once.
You could of course Mock any other dependency out using Moq and Assert on anything else you want to verify.

Guava's AsyncEventBus in tests

In our code messages travelling on guava's AsyncEventBus are frequently used. Now, in some of the tests some message traffic needs to finish, before assert on the state of the testee (say, some loads are scheduled on the EventBus, and these need to finish, so that we can test if things were loaded correctly).
Unfortunately, at the moment this is handled by the horrible Thread.sleep(delay); approach; very fragile and making tests flaky.
What would be the proper way to test code depending on completion of operations on common AsyncEventBus?
What I do in end-to-end or integration tests (multiple threads involved) where I need to wait until an event occurred is using a CountDownLatch. I would stay far away from sleeping threads as you've already mentioned.
This requires that in your test code you can hook the CountDownLatch.countDown() method into the callback method the EventBus is going to call. I explain that with a short example:
class SomeEventReceiver {
...
#Subscribe public void doSomethingFoo(BarEvent e) {
// your logic
}
...
}
// Unit test
...
CountDownLatch readyToAssert = new CountDownLatch(1); // could be 2 or more depending on your needs
SomeEventReceiver rec = new SomeEventReceiver(...) { // create an anonymous subclass
#Subscribe
#Override
public void doSomethingFoo(BarEvent e) { // override super method
super.doSomethingFoo(e); // execute super method's logic
readyToAssert.countDown(); // signal your test method that it's ready to assert
}
}
// put your events on the event bus and do all other necessary things
...
readyToAssert.await(); // JUnit thread is blocked until event handlers where called
assertXXX(...); // assert whatever needs to be asserted
That's my firsthand approach when testing. Obviously it's easier to do if the to-be-tested classes are designed in a testfriendly manner.
Hope that helped!

How to unit test an Akka actor that sends a message to itself, without using Thread.sleep

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.

How to unit test a synchronous method calling asynchronous method?

What is the correct way to write a unit test for a synchronous method calling async methods.
Right now my unit test are passing, but when I try to open the page, it never returns.
Why isn't my unit test failing? How can I make it fail?
I replicated my problem with this simple code:
My passing test:
[TestMethod]
public void DoSomeWork_WhenWeDoSomeWork_ShouldReturnDone()
{
var service = new SyncService();
const string expected = "Done";
var actual = service.DoSomeWork();
Assert.AreEqual(expected, actual);
}
My view that never returns:
public ActionResult Index()
{
var syncService = new SyncService();
return View((object)syncService.DoSomeWork());
}
My service that never returns to view:
public class SyncService
{
public string DoSomeWork()
{
return SomeWork().GetAwaiter().GetResult();
}
private async Task<string> SomeWork()
{
var task1 = Task.Delay(1000);
var task2 = Task.Delay(1000);
await Task.WhenAll(task1, task2);
return "Done";
}
}
I don't think I can help you with this specific example, but I think a good general strategy is to write two tests. One to test if the synchronous method passes the correct data and an other to test if the asynchronous method works properly.
I mostly work in JavaScript and that general approach works for me. Also you can check the documentation of your testing frameworks, maybe it provides some methods for this.
First, don't block on async code (link to my blog). By blocking on async code, you're actually causing a deadlock. This deadlock does not happen in your unit test because unit tests run in a thread pool context, not an ASP.NET context (link to my blog).
There are good reasons for not having synchronous wrappers for asynchronous methods. So I recommend getting rid of DoSomeWork completely, leaving only SomeWork (renamed to SomeWorkAsync).
To solve your problem, you should use asynchronous controller actions.

Mocking Prism Event Aggregator using Moq for Unit Testing

I need some advice on how to use Moq in a unit test to make sure that my class under test is behaving how I want. That is the class under test publishes an Event Aggregator (from Prism) event and I need some way of asserting that this event has been raised in my test.
I don't have a lot of resource at work and am finding it difficult to know how to set this up.
I have :-
public SomeEvent : CompositePresentationEvent<SomeEvent>
{
EventPayload
}
public SomeClass
{
void Allocate(){EventAggregator.Publish<SomeEvent>}
}
public SomeService : IService
{
SomeService(){ EventAggregator.Subscribe<SomeEvent>(DoSomething)}
void DoSomething(SomeEvent evt){}
}
I think that if my test is for SomeClass I need to verify that if I call SomeClass.Allocate a SomeEvent message is being published. How is this done?
Do I also need to verify that a mocked SomeService is receiving the SomeEvent? Or is that a seperate unit test that belongs to SomeService unit test and not SomeClass?
In any event, not sure how to set any of this up so any advice would be appreciated.
You would supply SomeClass with an IEventAggregator, which will allow you to supply a mock during testing:
public SomeClass(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
Then your test would look something like this:
var fakeEventAggregator = new Mock<IEventAggregator>();
var fakeEvent = new Mock<SomeEvent>();
fakeEventAggregator.
Setup(x => x.GetEvent<SomeEvent>()).
Returns(fakeEvent.Object);
var test = new SomeClass(fakeEventAggregator.Object);
test.Allocate();
fakeEvent.Verify(x => x.Publish(It.IsAny<SomeEventArgs>()));
If these are unit tests then you would test the subscription entirely separately in the SomeService tests. You are testing that SomeClass correctly publishes an event and that SomeService behaves correctly when it is given an event to process.