Namespace LaunchDarkly.TestHelpers.HttpTest
A simple portable HTTP test server with response mocking.
This namespace provides a simple abstraction for setting up embedded HTTP test servers that return programmed responses, and verifying that the expected requests have been made in tests.
The underlying implementation is System.Net.HttpListener
. There are other HTTP mock server libraries for .NET, most of which also use System.Net.HttpListener
either directly or indirectly, but they were generally not suitable for LaunchDarkly's testing needs due to either platform compatibility limitations or their API design.
An HttpServer is an HTTP server that starts listening on an arbitrarily chosen port as soon as you create it. You should normally do this inside a using
block to ensure that the server is shut down when you're done with it. The server's Uri property gives you the address for making your test requests.
You configure the server with a single Handler that receives all requests. The library provides a variety of handler implementations and combinators.
Examples
Invariant response with error status
var server = HttpServer.Start(Handlers.Status(500));
Invariant response with status, headers, and body
var server = HttpServer.Start(
Handlers.Status(202)
.Then(Handlers.Header("Etag", "123"))
.Then(Handlers.BodyString("text/plain", "thanks"))
);
Verifying requests made to the server
using (var server = HttpServer.Start(Handlers.Status(200)))
{
DoSomethingThatMakesARequest(server.Uri);
DoSomethingElseThatMakesARequest(server.Uri);
var request1 = server.Recorder.RequireRequest();
Assert.Equals("/path1", request1.Path);
var request2 = server.Recorder.RequireRequest();
Assert.Equals("/path2", request2.Path);
}
Response with custom logic depending on the request
var server = HttpServer.Start(
async ctx =>
{
if (ctx.RequestInfo.Headers.Get("Header-Name") == "good-value")
{
await Handlers.Status(200)(ctx);
}
else
{
await Handlers.status(400)(ctx);
}
}
);
Simple routing to simulate two endpoints
var server = HttpServer.Start(Handlers.Router(out var router));
router.AddPath("/path1", Handlers.Status(200));
router.AddPath("/path2", Handlers.Status(500));
Programmed sequence of responses
var server = HttpServer.Start(
Handlers.Sequential(
Handlers.Status(200), // first request gets a 200
Handlers.Status(500) // next request gets a 500
)
);
Changing server behavior during a test
using (var server = HttpServer.Start(Handlers.Switchable(out var switcher)))
{
switcher.Target = Handlers.Status(200);
// Now the server returns 200 for all requests
switcher.Target = Handlers.Status(500);
// Now the server returns 500 for all requests
}
Using a customized HttpClient instead of a server
var handler = Handlers.Record(out var recorder)
.Then(Handlers.BodyString("text/plain", "hello"));
var client = new HttpClient(handler.AsMessageHandler());
// Now all requests made with this client to any URI will receive the canned
// response, and can be inspected with the recorder.
Classes
Handler
An asynchronous function that handles HTTP requests to simulate the desired server behavior in tests.
Handlers
Factory methods for standard Handler implementations.
Handlers.SSE
Shortcut handlers for simulating a Server-Sent Events stream.
HandlerSwitcher
A delegator that forwards requests to another handler, which can be changed at any time.
HttpServer
A simplified wrapper for an embedded test HTTP server.
RequestInfo
Properties of a request received by a HttpServer.
RequestRecorder
An object that records all requests.
SimpleJsonService
A minimal framework for a JSON-based REST service.
SimpleResponse
Return type for endpoint handlers with SimpleJsonService.
SimpleResponse<T>
Return type for endpoint handlers with SimpleJsonService, when they return a value to be serialized as a response body.
SimpleRouter
A delegator that provides simple request path/method matching. The request is sent to the handler for the first matching path. If there is no matching path, it returns a 404. If there is a matching path but only for a different HTTP method, it returns a 405.
Interfaces
IRequestContext
An abstraction used by Handler implementations to hide the details of the underlying HTTP server framework.