Skip to content

Ensure public API surface using Approval-Tests

One of the things that made me think for some time is “How can I ensure my public REST-API does not change by accident?”.

Why

With todays IDE’s we have very powerfull automatic refactorings which is cool. The downside is that we easily can refactor a large pile of code what can affect the public API’s without the developer notice it.

When my public API’s (for example a REST-API’s my backend offers to partner companies) changes without notice it will be found very late the software development lifecycle. Worst case: after the release. This will result in a lot of work (and cost) for everybody involved.

The idea

So “Where is the problem?” you may ask: “Just write a bunch of unit-tests!”. The problem with this is that with the powerfull refactorings we usualy also refactor the unit-test code in one go. So the unit-test never becomes red even if we changed the public API. Therefore plain unit-tests are useless for this kind of tests.

We need something that does not get refactored automatically when we use automatic refactorings.

What I came up with is using ApprovalTests to dump the relevant data a in a approved-file (aka expectation file). This becomes our exectation of the unit-test result. The approval files don’t get changed by refactorings.

When they change I as a developer have to approve the new content manually (with the help of my diff tool) and therefore get noticed by my unit-test suite that something in the API changed.

How

ApprovalTests implementations are availlable for all major platoforms. For .Net you can install this Nuget package.

To test may REST-API’s I basically call action methods of my WebAPI controllers, serialize the output as Json and verify it using Approvals.

[UseReporter(typeof(DiffReporter))]
public class PersonControllerTests
{
    private readonly IPersonRepository personRepo = A.Fake<IPersonRepository>();
    private readonly PersonController controller;

    public PersonControllerTests()
    {
        controller = new PersonController(personRepo);
    }

    [Fact]
    public async Task GetDetails_Success_MustReturnObject()
    {
        // Arrange
        var personId = new Guid("51bd89eb-5ae6-4cfe-954a-f3f6a51352ab");

        // Act
        var result = await controller.GetDetails(personId)

        // Assert
        Approvals.VerifyJson(JsonConvert.SerializeObject(result));
    }
}

To enhace this one can also store the verb’s and URL’s. To do so you can wrap the above result in an anonymous object where you store additional information and serialize all of that into Json and approve it. It would be recommeded to implement a helper for doing this.

Alternative idea:

For REST-API’s an alternative idea is to generete the Swagger.json file you normaly need anyway and store it in your repo. Write a unit-tests that compares a freshly generated Swagger.json to the existing one. This would need some more advanced testing code / helpers but result in verify every aspect of the public API (Url’s, HTTP-Verbs, data-structures, supported headers, query-parameters, etc.)

One thought on “Ensure public API surface using Approval-Tests Leave a comment

  1. Cool! It is indeed a necessity when you develop the API for the external customers/consumers. If you are doing it for the internal purposes, you could also write Consumer Driven Contracts. That way you can ensure that either you didn’t break any consumers, or if you still don’t have any consumers, you can freely change the API to your liking.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: