.NET 5 API Authorization Integration Tests

Photo by Markus Spiske on Unsplash

It is obvious thing that during software creation life-cycle the code quality and proper functionality are the must. Besides of coding techniques like code reviews, MRs/PRs, pair programming, etc. various testing approaches are the must also. The QA teams or UAT tests are responsible for it at the end of coding process, but before it, the ones, who responsible for code quality are,
of course, developers.

An outcome of development is a “product” — properly working peace of software and in the era of micro-services, teams can decide about development approaches (Test-Driven-Development, Behavioral-Driven Development, Acceptance Test-Driven Development, etc.).

The “basic unit” for testing code is unit test. Coding techniques have changed during last years to make possible to cover you code (methods in a classes or units of code) by unit tests. Dependency injection and IoC containers is a “standard” (the techniques are similar in .NET or Java ecosystems) while it makes also possible convenient unit testing.

Next step, is testing if cooperation of software components in a bigger functionality. For example, REST API method that reads data from another REST and asynchronously writes it to some Message Broker and Database. All methods used in this “process” are covered by Unit Tests, but overall “cooperation” them starting from API entry point are not. And here developers start to write Integration Tests (or Integration Tests are already written, if you use TDD or BDD).

End to End tests (E2E) — are the next degree of your software functional tests and it is very useful if they are automated during CI/CD pipelines execution. But, of course, it depends :).

Load and stress testing that is another type of non functional tests that characterize the quality of you software. While it is not a part of this post let me redirect you here.

And a little bit more about Unit vs Integration vs System vs E2E Testing comparison from MS.

Here I concentrate on integration tests of Web API example with Azure AD authorization, authentication and how to arrange it in a simple and readable way.

Lets imagine that we have CRUD API controller for some user notes for abstract documents. It is simply a title and description for document that user stores, something like this:

The Azure Ad Scopes configured for access_as_user and access_as_admin. Web API applications here consists of three tiers: NotesControler, NotesService and NotesRepository with MongoDB configured underneath.

The overall code you can find on the GitHub: Compentio.Ferragosto.Notes

The integration tests for getting notes method could be like this:

Few things here we should note:

  • WebApplicationFactory — factory for bootstrapping an application in memory for functional and integration tests
  • _httpClient — HTTP client created using WebApplicationFactory extensions for authentication and mocking services — code snippets are below
  • _notesRepositoryMock — mocks for repository.

WebApplicationFactory boostraps in memory HTTP web server, but for our scenario with authorization and authentication that’s not enough cause we need to check proper and invalid (unauthorized and unauthenticated) requests to our API. To cover it I’ve added WithAuthentication() and WithAuthenticationWithoutClaims() extensions methods for factory:

These methods use different AuthenticationHandlers: TestAuthenticationHandler for proper authentication and TestAuthenticationHandlerWithoutClaims for user, that does not have required claims. The handlers are below:

here it is important to use claim type in line 13 as “http://schemas.microsoft.com/identity/claims/scope” for Azure AD access_as_user scope. In the TestAuthenticationHandlerWithoutClaims we do not add required in NotesController access_as_user scope and in test case ShouldBeForbidden (line 53 in NotesApiIntegrationTests) we expect Forbidden response.

ShouldBeUnauthorized() method does not configured to use any authentication handler, thus we expect Unauthorized 401 error and, obviously, no any interaction with _notesRepository:

Here we covered three basic auth scenarios for API requests of one GET method: 200 OK, 401 Unauthorized and 403 Forbidden. From my experience, it is important always to keep such tests in code and execute them during CI/CD pipelines, since it prevents us from accidental (which, unfortunately, occurs often) removal of Authorize or RequiredScope controller attributes.

Obviously, in a real web apps integration testing scenarios, more test needed: e.g. validation tests (BadRequest), server unexpected errors (500), empty lists or NotFound for one entity, ect.

In the post I’d like to show how we use WebApplicationFactory to arrange integration tests for different authorization scenarios. For testing and mocks I’ve used:

  • xUnit
  • Moq
  • Fluent Assertions
  • Bogus

For mocking also I propose to use “Fluent Mocking” like this:

Photo by Manuel Cosentino on Unsplash