Repository navigation
Configuring Responses
Responses are configured on server.Mock in two parts: which request (Send...), then what to do (Receive...,
Disconnect() or NoReply()).
server.Mock.Send("version").Receive("1.0.0");You can configure responses before or after Start(), and from any thread.
using var server = new MockServer(new TcpServer(0));
server.Mock.Send("version").Receive("1.0.0");
server.Mock.Send(new byte[] { 0x01, 0x02 }).Receive(new byte[] { 0x03, 0x04 });
server.Start();
using var client = await TcpTestClient.ConnectAsync(server.Port);
Assert.Equal("1.0.0", await client.SendAndReceiveAsync("version"));
await client.SendAsync(new byte[] { 0x01, 0x02 });
Assert.Equal(new byte[] { 0x03, 0x04 }, await client.ReceiveBytesAsync());Text is sent as UTF-8. Requests are compared byte for byte, so binary data that isn't valid text works too.
Pass a function to build the response from the request, as text or as bytes:
server.Mock.Send("hello").Receive(text => text.ToUpper());
server.Mock.Send(new byte[] { 1, 2, 3 }).Receive(bytes => bytes.Reverse().ToArray());The function runs on every request, so it can also keep state:
var counter = 0;
server.Mock.Send("next").Receive(_ => $"#{++counter}"); // "#1", "#2", ...If the function throws, the response is empty. Over TCP, nothing is sent.
Note: an identity lambda such as
x => xis ambiguous, because it fits bothFunc<string, string>andFunc<byte[], byte[]>. Give the parameter a type:Receive((byte[] request) => request).
Send(""), an empty request, matches anything that has no more specific response:
server.Mock.Send("known").Receive("specific answer");
server.Mock.Send("").Receive("ERROR unknown command");Combined with a function, it makes an echo server:
server.Mock.Send("").Receive((byte[] request) => request);If a request has no matching response and there is no Send("") default:
- TCP: the connection is closed without sending anything.
- UDP: an empty datagram is sent back.
The request is still recorded, with Matched == false, so you can detect it with
server.Should().HaveNoUnmatchedRequests().
using var server = new MockServer(new TcpServer(0));
server.Mock.Send("known").Receive("yes");
server.Start();
using var client = await TcpTestClient.ConnectAsync(server.Port);
await client.SendAsync("unknown");
Assert.Equal("", await client.ReadToEndAsync());- The same exact request can only be configured once; a second
Send("ping").Receive(...)throwsArgumentException. To return different responses over time, use a sequence. -
Receive(...)without aSend(...)before it throwsInvalidOperationException. - An empty response (
Receive("")) sends nothing over TCP and an empty datagram over UDP. -
server.Mock.Reset()removes every response and recorded request.
server.Mock.Reset();
Assert.Empty(server.Mock.Configs);
Assert.Empty(server.Mock.ReceivedRequests);server.Mock.Send(...) // or SendMatching(...), SendMatchingBytes(...), Send(Regex)
.Receive(...) // or Disconnect(), NoReply()
.After(TimeSpan) // delay that response
.AndDisconnect() // close the connection after that response
.Then(...) // next response: text, bytes or a function
.ThenDisconnect() // next time: close without replying
.ThenNoReply(); // next time: stay silentMore on each part:
- Request Matching: regex, predicates and which response wins.
-
Response Sequences:
Then(...). -
Simulating Failures:
After,Disconnect,NoReply,AndDisconnect.
server.Mock.Match(request) runs the same lookup the server does and returns the response bytes. It also records the
request and moves sequences forward, just like a real request.
Runnable code: ResponseSamples.cs