This library contains extensions to the FluentAssertions library, that makes it easier to assert against the ResultBase
types returned from domain handlers.
The domain handlers generated by ATC always return a type that inherits from ResultBase
. That type is the extension point for the following assertion methods:
-
result.Should().BeOkResult()
: Verifies that theresult
object is aOkObjectResult
type with a status code of 200. -
result.Should().BeAcceptedResult()
: Verifies that theresult
object is aContentResult
type with a status code of 202. -
result.Should().BeNoContentResult()
: Verifies that theresult
object is aContentResult
type with a status code of 204. -
result.Should().BeBadRequestResult()
: Verifies that theresult
object is aContentResult
type with a status code of 400. -
result.Should().BeNotFoundResult()
: Verifies that theresult
object is aContentResult
type with a status code of 404. -
result.Should().BeConflictResult()
: Verifies that theresult
object is aContentResult
type with a status code of 409.
To access the result object, use the standard Subject
property, e.g. result.Should().BeOkResult().Subject
. The usual standard FluentAssertions properties, such as Which
, And
, are also available where appropriate.
To help verify the content in a result, use the WithContent
method, which accepts the expected content directly, e.g. result.Should().BeOkResult().WithContent(expected)
.
The "error result types", e.g. bad request and not found, also has a WithErrorMessage
method, that helps verify a custom error messages.
The following example will show how to test the following a simple GetAllItemsByCategory
handler:
public class GetAllItemsByCategoryHandler : IGetAllItemsByCategoryHandler
{
private readonly IRepository repository;
public GetAllItemsByCategoryHandler(IRepository repository)
{
this.repository = repository ?? throw new ArgumentNullException(nameof(repository));
}
public Task<GetAllItemsByCategoryResult> ExecuteAsync(GetAllItemsByCategoryParameters parameters, CancellationToken cancellationToken = default)
{
if (parameters is null)
{
throw new ArgumentNullException(nameof(parameters));
}
return InvokeExecuteAsync(parameters, cancellationToken);
}
private async Task<GetAllItemsByCategoryResult> InvokeExecuteAsync(GetAllItemsByCategoryParameters parameters, CancellationToken cancellationToken)
{
List<Item>? result = await repository.GetByCategory(parameters.Category);
return result is not null
? GetAllItemsByCategoryResult.OK(result)
: GetAllItemsByCategoryResult.NotFound("Invalid category");
}
}
This handler basically uses a repository to try to find items based on a category. The repository will return null as the result if the category does not exist.
To verify the data returned from the repository is correctly returned from the handler, do the following:
[Fact]
public async Task Should_Return_OK_And_Content_From_Repository()
{
// Arrange
var items = new[] { new Item() { Category = "Foo" } };
var repository = new FakeRepository(items);
var sut = new GetAllItemsByCategoryHandler(repository);
// Act
var result = await sut.ExecuteAsync(new GetAllItemsByCategoryParameters { Category = "Foo" });
// Assert
result
.Should()
.BeOkResult()
.WithContent(items);
}
In the above example, the BeOkResult
method is used to verify that the result is a OkObjectResult
type with a status code of 200. Then the WithContent
method is used to verify that the content in the OK result is the same as the expected items
collection.
The WithContent
uses the BeEquivalentTo
method from FluentAssertions that does a structural comparison, since the content in the OK result is serialized to JSON.
To verify that a 404 NOT FOUND response is returned when the repository returns null, do the following:
[Fact]
public async Task Should_Return_NotFound_When_Category_Isnt_In_Repository()
{
// Arrange
var repository = new FakeRepository();
var sut = new GetAllItemsByCategoryHandler(repository);
// Act
var result = await sut.ExecuteAsync(new GetAllItemsByCategoryParameters { Category = "Bar" });
// Assert
result
.Should()
.BeNotFoundResult()
.WithErrorMessage("Invalid category");
}
In the example above, the BeNotFoundResult
method is used to check that the result type is a ContentResult
type, with a status code of 404.
If you provide a custom error message to the NotFound
method in the handler, this can be verified with the WithErrorMessage
method, as shown here.