| Image by Clay Banks via Unsplash Copyright-free
Controller integration tests using an embedded test server
The payout platform team have very few controller endpoints for adapters, but some of the ones we do have are quite important! In particular, we have correspondent APIs asynchronously calling us when a state-change occurs for a customer's payment.
Each adapter that adheres to this async principle has a
CallbackController - typically pretty skinny, with just one primary public method and probably a healthcheck/heartbeat of some kind.
It's reasonably simple to write unit tests for controllers nowadays, so this isn't going to focus on that as I'm sure anyone reading this knows exactly how to do that, with your favourite flavour of mocking library.
It's slightly more difficult to have something that is self-contained and does not require a mountain of setup and clunky test-only 'state' - but .NET Core provides something pretty great that will bridge most of these gaps, which are the
WebHost types that are part of
Microsoft.AspNetCore.Mvc.Testing, which is available as a nuget package.
Consider this controller action that accepts a message (in this case it's XML, but it could be any serializable/parseable message)
It's nice to test this from the point of view of a http call for a number of reasons - you can ensure the routing is correct (obvious perhaps, but still useful), and you can throw different shapes and sizes of message at it, some valid, some invalid - then ensure that each scenario is handled properly.
Since we're working with something that has a lot of structure (i.e a .NET Core application) - we do need some setup. This can be distilled down a little, but ultimately will look something like this:
There's slightly more to the full test fixture than the above, so please refer to the GitHub repository link for the complete setup required.
Please note that when we create the TestServer we must pass in a TestHost and not an IServiceCollection, as the collection overload will not allow us to create a TestClient.
In the following method we setup our mocks, as well as our test server's HttpClient [docs], and pass these back to any calling tests as a simple value type. From this we can then call the http client we've created with both good and bad payloads to simulate exactly how our client will behave in real life.
As we can see from the above, we build up our simple test client, create a real XML payload and POST this to the endpoint "/api/callback/status", and ensure that our payout API mock received the message that we expected.
Authors: Matt Millross, Chris Booth