This time I have a C# async method that should be tested. As you remember, async method must return Task or Task<>. You can declare an async void method, but this should be used only for event handlers because you have no control on method execution and, the most important, its failure. Beside that, async void method is hard to test.
I have a simple async method that returns Task<int> instead of int in synchronous method (look at my previous post Unit Testing C# Synchronous Methods).
1 2 3 4 5 6 7 8 9 10 11 |
public async Task<int> GetNumberAsync(int number) { await Task.Delay(100); if (number < 0) { throw new ArgumentException(); } return number; } |
We must be happy that modern unit test frameworks allow to write async unit test where an async method is called asynchronously.
1. Check successful result
1 2 3 4 5 6 7 8 9 10 |
[Fact] public async Task GetNumberAsync_Success() { // arrange var sut = new SystemUnderTest(); // act int actual = await sut.GetNumberAsync(5); // assert Assert.Equal(5, actual); } |
The async method being tested is called via await operator. This makes the code being executed in true asynchronous mode.
2.1. Check failure with ThrowsAsync<>
1 2 3 4 5 6 7 8 |
[Fact] public async Task GetNumberAsync_Fail_Throws() { // arrange var sut = new SystemUnderTest(); // act & assert await Assert.ThrowsAsync<ArgumentException>(async () => await sut.GetNumberAsync(-1)); } |
Unit test is awaiting for result from Assert.ThrowsAsync, that is awaiting for result from the method being tested. If you delete the inner async/await, the method would be executed in synchronous mode. If you omit the first outer await, the unit test method might finish before the code in NumberAsync would fail. So you will get wrong results!
2.2. Check failure with Record.ExceptionAsync
1 2 3 4 5 6 7 8 9 10 11 |
[Fact] public async Task GetNumberAsync_Fail_Record() { // arrange var sut = new SystemUnderTest(); // act var exception = await Record.ExceptionAsync(async () => await sut.GetNumberAsync(-1)); // assert Assert.NotNull(exception); Assert.IsType<ArgumentException>(exception); } |