Beyond Simple Asserts with ApprovalTests

In a test, we are often testing (asserting) individual items such as an (int) age is correct or a string matches an expected value.

If we are practicing test-first development we’ll write our asserts first.

Approval tests allow us to go beyond simple asserts.

What if the thing we’re checking is not a simple value, for example that a pie chart image matches the input data? Or what if we want to use our human judgement to decide when something looks correct, something that is hard to codify in one or more basic asserts?

ApprovalTests for .NET can be install via NuGet. Once installed, it gives us a whole new world when it comes to checking the output of code.

For example, say we are developing a class to represent a stickman. We want to be able to tell an instance to raise left arm or raise right leg for example.

Example of Using Approval Tests

So lets start with a test:

[Fact]
[UseReporter(typeof(DiffReporter))]
public void ShouldHaveDefaultPosture()
{
    var sut = new StickMan();

    Approvals.Verify(sut);
}

And an empty StickMan:

public class StickMan
{        
}

Here we’re using xUnit.net (the [Fact] attribute) but you could be using NUnit for example.

The first thing to notice here is there is no traditional Assert method, instead we’re using Approval Tests to verify the state of the system under test (sut).

The other think to notice is the [UseReporter] attribute that tells Approval Tests to use a diff tool to display errors when a test fails.

If we run this test, we’ll get a diff tool opened:

Diff tool screenshot

On the left is the result of the test (in a “received” file), on the right is what we expected (in an “approved” file).

Now we can edit the approved file and create what we want our stickman to look like:

Diff tool screenshot

The default overload of the Approvals.Verify() method will call ToString() on our SUT.

So now we can output the “model state” of our stickman:

public class StickMan
{
    public override string ToString()
    {
        var sb = new StringBuilder();

        sb.AppendLine( " O");
        sb.AppendLine(@"/|\");
        sb.AppendLine( " |");
        sb.Append(@"/ \");

        return sb.ToString();
    }
}

Now when we run the test again, the received file will contain our ASCII art stickman, it will match the approved file, and the test passes. The diff tool won’t be opened as the test passed.

passing test

Now we can write our next test:

[Fact]
[UseReporter(typeof(DiffReporter))]
public void ShouldRaiseLeftArm()
{
    var sut = new StickMan();

    sut.RaiseLeftArm();

    Approvals.Verify(sut);
}

If we add this new test it will fail because we don’t have an approved version. We can modify and save the approved file:

Diff tool screenshot

 

And now write the code to make the test pass:

public class StickMan
{
    private bool _isLeftArmRaised;

    public override string ToString()
    {
        var sb = new StringBuilder();

        if (_isLeftArmRaised)
        {
            sb.AppendLine(@"\O");
            sb.AppendLine(@" |\");                
        }
        else
        {
            sb.AppendLine( " O");
            sb.AppendLine(@"/|\");                
        }

        sb.AppendLine( " |");
        sb.Append(@"/ \");

        return sb.ToString();
    }

    public void RaiseLeftArm()
    {
        _isLeftArmRaised = true;
    }
}

The test now passes because the approved file matches the received file.

If we introduce an error (lets change the legs):

sb.Append(@"< >");

And run the test, it will now fail and the diff tool shows us what’s wrong:

Diff tool screenshot

 

This is just scratching the surface of the power of Approval Tests, there’s a whole heap of other features that help to test images, application views, and even help get legacy code under test.

For more information check out the website, or my Approval Tests for .NET Pluralsight course, and be sure to say a thankyou to @LlewellynFalco.

Pingbacks and trackbacks (1)+

Add comment

Loading