Getting Started

Add the package, then use BunsenBurner in each test file that needs it,

dotnet add package BunsenBurner

// for AAA style tests
using static BunsenBurner.ArrangeActAssert;

or the Given/When/Then spelling,


// for BDD style tests
using static BunsenBurner.GivenWhenThen;

Take an existing test,


[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,
        cancellationToken: TestContext.Current.CancellationToken
    );

    // Assert
    Assert.Equal(
        expected: "{\"Name\":\"Widget1\",\"Cost\":12.5}",
        actual: Encoding.UTF8.GetString(ms.ToArray())
    );
}

This can be converted to use the test builder (DSL) like so,


[Fact(DisplayName = "SerializeAsync can work with anonymous objects")]
public Task ExampleTestUsingAaaBuilder() =>
    Arrange(() =>
        {
            var widget = new { Name = "Widget1", Cost = 12.50 };
            var ms = new MemoryStream();
            return (widget, ms);
        })
        .Act(async data =>
        {
            await JsonSerializer.SerializeAsync(data.ms, data.widget);
            return Encoding.UTF8.GetString(data.ms.ToArray());
        })
        .Assert(result =>
            Assert.Equal(expected: "{\"Name\":\"Widget1\",\"Cost\":12.5}", actual: result)
        );

Note

Tests must always return a Task to be compatible with the DSL.

This formalizes the structure and then opens up refactoring possibilities such as pulling out a shared act method,


[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());
}

The idea is to use the DSL to make the shape of the test explicit, then use that shape to find code that can be shared.