yes

Automate Swagger/OpenApi snapshot testing

Adding OpenApi/Swagger spec generator into an Asp.Net Core app is easy. It even comes preconfigured with the Asp.Net Core 5 template.

Both Swashbuckle and NSwag offer quite easy extension points to further customize the spec generation. For example you can add 401 and 403 response types automatically based on the [Authorize] attribute. This saves you from manually decorating all the methods.

After adding extra smarts into the spec generation process, it would be great to set up tests that let you know when the spec starts to drift. Similarly to how Jest does snapshot testing in React.

To set up the snapshot testing, you first need to take the initial snapshot:

public class BasicTests 
    : IClassFixture<WebApplicationFactory<RazorPagesProject.Startup>>
{
    private readonly WebApplicationFactory<RazorPagesProject.Startup> _factory;
    private string SnapshotPath => 
        $"{AppDomain.CurrentDomain.BaseDirectory}../../../snapshots/swagger.snap.yaml";

    public BasicTests(WebApplicationFactory<RazorPagesProject.Startup> factory)
    {
        _factory = factory;
    }

    [Fact]
    public async Task Write_Snapshot(string url)
    {
        var client = _factory.CreateClient();
        var response = await client.GetAsync("/swagger/v1/swagger.yaml");
        string openApiSpec = await response.Content.ReadAsStringAsync();
        await WriteNewSnapshot(openApiSpec);
    }

    private async Task WriteNewSnapshot(string openApiSpec)
    {
        await File.WriteAllTextAsync(SnapshotPath, openApiSpec);
    }

After writing the initial snapshot you can read that and compare it to the current one. To print out a nice diff, you can use the Diff Match Patch from Google.

private List<Diff> GetDiffs(string openApiSpec, string snapshot)
{
    diff_match_patch dmp = new diff_match_patch();
    List<Diff> diffs = dmp.diff_main(openApiSpec, snapshot);
    dmp.diff_cleanupSemantic(diffs);

    foreach (var diff in diffs.Where(diff => diff.operation != Operation.EQUAL))
    {
        _output.WriteLine($"==={diff.operation}===");
        _output.WriteLine(diff.text);
    }

    return diffs;
}

The end result should look something similar:

Additional Info:
    Spec differs from the snapshot
    ...
===INSERT===
        '404':
          description: Not Found
          ...

===DELETE===
  /orders/foo:
    get:
      responses:
        '500':
          description: Server Error
          ...