Records and replays successful HTTP responses in your testing environment.
In a micro-service context, where your integration tests depend on a lot of external HTTP resources, Cassette is an ideal tool to improve the stability of your CI pipeline. It is based on a very simple idea: uniquely identify all the requests that pass through and record succesfull reponses. After recording, replay the same responses without actually calling the real REST endpoint.
To create that unique request identifier, Cassette computes an hash from the HTTP method, the uri and the body.
- Improves the stability of your testing environment.
- Speeds up the execution of your test suite.
- Avoids to many calls to your HTTP API dependencies, each time your CI pipeline runs.
Cassette is available as a single NuGet package.
Install-Package Cassette.Http
- .NET Core 2.1+ or .NET 4.6.1+
- Register an implementation of
IDistributedCache
(Redis, SQL Server, in-memory).
- The easiest way to configure Cassette is to use the HttpClientFactory. It will allow you to add the
ReplayingHandler
to everyHttpClient
. A sample that also uses Refit is available here.
services.AddRefitClient<IGeoApi>()
.ConfigureHttpClient(options => options.BaseAddress = new Uri("https://geo.api.gouv.fr"))
.AddReplayingHttpMessageHandler(); // Add the replaying message handler for the the IGeoApi, only
// if Cassette has been previously registered by calling AddCassette().
// The idea is to activate Cassette only during the integration tests.
Until the
AddCassette()
configuration method has been called, the HTTP message handler is not really added to the HttpClient, so its behavior remains unchanged.
- Finally activate Cassette during integration tests, by calling the
AddCassette()
configuration method before the registration of the message handlers. You can either use a feature toggle or even better create an integration test project to override your DI configuration. Another sample can be found here.
// Declare the cache implementation Cassette will rely on
services.AddDistributedMemoryCache();
// Register Cassette in the DI container
services.AddCassette(options =>
{
options.KeyPrefix = "Cassette";
options.CacheEntryOption.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);
});
Cassette uses specific HTTP request headers to modify its behavior. They are defined in the classes CassetteOptions
and CassetteOptions.Refit
:
- NoRecord: prevent caching of the HTTP response.
- ExcludeRequestBody: exclude the request body from the computed key in cache when it contains an auto-generated identifier that would cause cache misses.
- ExcludeLastUriSegment: exclude from the computed key in cache the last uri segment when its value is always different between calls, causing cache misses.
public interface IGeoApi
{
[Get("/regions")]
Task<List<Region>> GetRegions();
[Headers(CassetteOptions.Refit.NoRecord)]
[Post("/regions")]
Task CreateRegion(Region region);
}