wsmock
March 22, 2026 · View on GitHub
wsmock is an expressive, zero-boilerplate WebSocket mock server for Go testing. It provides a declarative scenario builder and fault injection engine (network drops, slow responses, abnormal closure codes) to make testing WebSocket clients and services effortless.
Features
- Zero Setup: Start an in-memory WebSocket mock server with one line (
wsmock.NewServer(t)). - Declarative Expectations: Mock request-response patterns with
ExpectMessage,ExpectJSON, orExpectBinary. - Chaos and Fault Injection:
DropConnection(): Abruptly drops the underlying TCP socket without an RFC close frame (ideal for testing auto-reconnect logic).CloseWithCode(code, reason): Sends RFC 6455 close frames (e.g.,1008 Policy Violation,1011 Server Error).Delay(d): Simulates network latency and slow responses.
- Broadcast and Streaming: Push unprompted events to connected clients.
- Recorded History and Assertions: Inspect and assert received payloads and expectation fulfillment.
- Thread-Safe: Fully safe for concurrent test execution and tested with
-race.
Installation
go get github.com/sing198/wsmock
Quick Start
1. Basic Request & Reply
func TestClientEcho(t *testing.T) {
srv := wsmock.NewServer(t)
// Set up expectation
srv.ExpectMessage("ping").Reply("pong")
// Connect client to srv.URL()
conn, _, err := websocket.DefaultDialer.Dial(srv.URL(), nil)
require.NoError(t, err)
defer conn.Close()
// Send and verify
_ = conn.WriteMessage(websocket.TextMessage, []byte("ping"))
_, reply, _ := conn.ReadMessage()
assert.Equal(t, "pong", string(reply))
// Assert that the expected message was received
srv.AssertExpectationsMet()
}
2. Testing JSON Payloads
type AuthRequest struct {
Token string `json:"token"`
}
type AuthResponse struct {
Success bool `json:"success"`
}
func TestClientAuth(t *testing.T) {
srv := wsmock.NewServer(t)
srv.ExpectJSON(AuthRequest{Token: "secret"}).
ReplyJSON(AuthResponse{Success: true})
// ... dial and test your client ...
}
3. Fault Injection: Testing Reconnection Logic
Simulate abrupt network cuts without an RFC close frame to ensure reconnection clients recover gracefully:
func TestClientReconnectOnNetworkLoss(t *testing.T) {
srv := wsmock.NewServer(t)
// Abruptly sever the TCP connection upon receiving "trigger-drop"
srv.ExpectMessage("trigger-drop").DropConnection()
// Or close with specific close code:
// srv.ExpectMessage("forbidden").CloseWithCode(websocket.ClosePolicyViolation, "denied")
// Run client under test...
}
4. Broadcasting & Server Pushes
func TestServerStreaming(t *testing.T) {
srv := wsmock.NewServer(t)
// Broadcast messages to all active connections
srv.Broadcast("ticker-update:100.5")
// Or broadcast structured JSON
srv.BroadcastJSON(MyEvent{Type: "price", Value: 100.5})
}
License
MIT © Thanaphat Khunphet