Mock Sockets
The mocket class provides mock sockets for testing I/O code without
actual network operations. Mockets let you stage data for reading and
verify expected writes.
| Code snippets assume: |
#include <boost/corosio/test/mocket.hpp>
#include <boost/capy/test/fuse.hpp>
namespace corosio = boost::corosio;
namespace capy = boost::capy;
Overview
Mockets are testable socket-like objects:
// Create connected pair
capy::test::fuse f;
auto [client, server] = corosio::test::make_mockets(ioc, f);
// Stage data on server for client to read
server.provide("Hello from server");
// Stage expected data that client should write
client.expect("Hello from client");
// Now run your code that uses client/server as io_stream&
Creating Mockets
Mockets are created in connected pairs:
corosio::io_context ioc;
capy::test::fuse f;
auto [m1, m2] = corosio::test::make_mockets(ioc, f);
The pair is connected via loopback TCP sockets. Data written to one can be read from the other, plus you can use the staging/expectation API.
Staging Data for Reads
Use provide() to stage data that the peer will read:
// On server: stage data for client to read
server.provide("HTTP/1.1 200 OK\r\n\r\nHello");
// Now when client reads, it gets this data
auto [ec, n] = co_await client.read_some(buffer);
// buffer contains "HTTP/1.1 200 OK\r\n\r\nHello"
Multiple provide() calls append data:
server.provide("Part 1");
server.provide("Part 2");
// Client sees "Part 1Part 2"
Setting Write Expectations
Use expect() to verify what the caller writes:
// Client should send this exact data
client.expect("GET / HTTP/1.1\r\n\r\n");
// Now client writes
co_await corosio::write(client, request_buffer);
// If written data doesn't match, fuse fails
Closing and Verification
Use close() to verify all expectations were met:
auto ec = client.close();
if (ec)
std::cerr << "Test failed: " << ec.message() << "\n";
The close() method:
-
Closes the underlying socket
-
Checks that
provide()buffer is empty (all data read) -
Checks that
expect()buffer is empty (all expected data written) -
Returns error and calls
fuse.fail()if verification fails
The Fuse
Mockets work with capy::test::fuse for error injection:
capy::test::fuse f;
auto [m1, m2] = corosio::test::make_mockets(ioc, f);
// The first mocket (m1) calls f.maybe_fail() on operations
// This enables systematic error injection testing
The second mocket (m2) doesn’t call maybe_fail(), allowing asymmetric
testing.
Complete Example
#include <boost/corosio/test/mocket.hpp>
#include <boost/capy/test/fuse.hpp>
capy::task<void> test_http_client()
{
corosio::io_context ioc;
capy::test::fuse f;
auto [client, server] = corosio::test::make_mockets(ioc, f);
// Client should send this request
client.expect(
"GET / HTTP/1.1\r\n"
"Host: example.com\r\n"
"\r\n");
// Server will respond with this
server.provide(
"HTTP/1.1 200 OK\r\n"
"Content-Length: 5\r\n"
"\r\n"
"Hello");
// Run the code under test
co_await my_http_get(client, "example.com", "/");
// Verify expectations
auto ec1 = client.close();
auto ec2 = server.close();
if (ec1 || ec2)
throw std::runtime_error("Test failed");
}
Testing with io_stream Reference
Since mocket inherits from io_stream, you can pass it to code expecting
streams:
// Your production code
capy::task<void> send_message(corosio::io_stream& stream, std::string msg)
{
co_await corosio::write(
stream, capy::const_buffer(msg.data(), msg.size()));
}
// Test code
capy::task<void> test_send_message()
{
auto [client, server] = make_mockets(ioc, f);
client.expect("Hello, World!");
co_await send_message(client, "Hello, World!");
auto ec = client.close();
assert(!ec);
}
Thread Safety
Mockets are NOT thread-safe:
-
Use from a single thread only
-
All coroutines must be suspended when calling
expect()orprovide() -
Designed for single-threaded, deterministic testing
Limitations
-
Data staging is one-way (provide on one side, read on the other)
-
No simulation of partial writes or network delays
-
Connection errors must be injected via fuse
Use Cases
Unit Testing Protocol Code
// Test that your protocol parser handles responses correctly
server.provide("200 OK\r\nContent-Type: text/html\r\n\r\n<html>...</html>");
co_await my_protocol_read(client);
// Verify parsed result
Next Steps
-
Sockets Guide — The socket interface mockets implement
-
Error Handling — Testing error paths