1

I have a try/catch block in both my application and unit test. I'm trying to create a test that catches an exception being thrown in my actor. When debugging through the code I get the exception being thrown but in my test I never receive the exception.

Application:

public class FooActor : ReceiveActor {
    private readonly IFooService fooService;
    private readonly IChildActorFactory childCreatorFactory;
    private IActorRef barActor;

    public FooActor(IFooService fooService, IChildActorFactory childCreatorFactory) {   
        this.fooService = fooService;
        this.childCreatorFactory = childCreatorFactory;

        ReceiveAsync<bool>(async (x) => await StartAsync(x).ConfigureAwait(false));
    }

    protected override void PreStart() {
        barActor = childCreatorFactory.Create<BarActor>(Context, "BarActor");
    }

    public async Task StartAsync(bool start) {
        try {
            if (start) {
                var fooInformation = await fooService.GetInformationAsync().ConfigureAwait(false);

                if (fooInformation != null) {
                    barActor.Tell(fooInformation);
                }
            }
        } catch (Exception exception) {
            throw new Exception($"Unhandled exception. Actor {Self.Path.Name};", exception);
        }
    }
}

Test:

[Fact]
public void StartAsync_ThrowsException_ExceptionThrown() {
    using (var mock = AutoMock.GetLoose()) {
        //Arrange
        Sys.UseAutofac(mock.Container);
        var mockChildActorFactory = mock.Mock<IChildActorFactory>();
        var mockBarService = mock.Mock<IBarService>();

        mockBarService.Setup(x => x.GetInformationAsync()).Throws(new Exception());

        var props = Props.Create(() => new FooActor(mockBarService.Object, mockChildActorFactory.Object));

        var fooActorName = "FooActor";
        var fooActor = new TestActorRef<FooActor>(Sys, props, null, fooActorName);

        try {
            // Act
            fooActor.Receive(true);
        } catch (Exception exception) {
            // Assert
            Assert.Equal($"Unhandled Exception. Actor { fooActorName }.", exception.Message);
        }
    }
}
Jeffrey Chung
  • 19,319
  • 8
  • 34
  • 54
Tommy Tran
  • 11
  • 3

1 Answers1

0

The problem is in the async/await operators in ReceiveAsync method:

ReceiveAsync<bool>(async (x) => await StartAsync(x).ConfigureAwait(false));

when execution context reached the await operation it just start Task at thread pool(simplified) and returns to the caller. I.e. when

fooActor.Receive(true);

completed, the actual task with StartAsync(x) may not be started yet. So when actual exception is thrown your test is already finished without any exception.

Sergey Popov
  • 538
  • 5
  • 14