Why?
Most tests in C# are written in an arrange, act, assert style, like so,
[Fact(DisplayName = "SerializeAsync can work with anonymous objects")]
public async Task ExampleTest()
{
// Arrange
var widget = new { Name = "Widget1", Cost = 12.50 };
var ms = new MemoryStream();
// Act
await JsonSerializer.SerializeAsync(ms, widget);
// Assert
Assert.Equal(
expected: "{\"Name\":\"Widget1\",\"Cost\":12.5}",
actual: Encoding.UTF8.GetString(ms.ToArray())
);
}
This structure is only a convention and is not enforced by the test framework.
This library aims to formalize this structure in the following ways,
- Enforces that all tests must be arranged before acting and acted upon before assertions can occur. Making it a compile-time error if this is not followed
- Scaffolding tests using a fluent API making them easier to read, write and refactor
- Encourages automatic refactoring of tests sections into helper methods, which is only possible if the test is structured using delegates
- Works with the developers IDE to provide a better experience when writing tests
[Fact(DisplayName = "SerializeAsync can work with anonymous objects")]
public Task ExampleTestUsingAaaBuilder2() =>
Arrange(() =>
{
var widget = new { Name = "Widget1", Cost = 12.50 };
var ms = new MemoryStream();
return (widget, ms);
})
// pull out the shared test code
.Act(CallSerializeAsync)
.Assert(result =>
Assert.Equal(expected: "{\"Name\":\"Widget1\",\"Cost\":12.5}", actual: result)
);
// this is now a shared stage and can be used in many tests
private static async Task<string> CallSerializeAsync<T>((T, MemoryStream) data)
{
var (widget, ms) = data;
await JsonSerializer.SerializeAsync(ms, widget);
return Encoding.UTF8.GetString(ms.ToArray());
}