Testing Micro Services
The testing package provides utilities for testing micro services in isolation.
Quick Start
import (
"testing"
"go-micro.dev/v6/test"
)
func TestGreeter(t *testing.T) {
h := test.NewHarness(t)
defer h.Stop()
h.Name("greeter").Register(new(GreeterHandler))
h.Start()
var rsp HelloResponse
err := h.Call("GreeterHandler.Hello", &HelloRequest{Name: "World"}, &rsp)
if err != nil {
t.Fatal(err)
}
if rsp.Message != "Hello World" {
t.Errorf("expected 'Hello World', got '%s'", rsp.Message)
}
}
How It Works
The harness creates isolated instances of:
- Registry - In-memory registry for service discovery
- Transport - HTTP transport for RPC
- Broker - In-memory broker for events
This allows your service to run without affecting or being affected by other services.
API
Creating a Harness
h := test.NewHarness(t)
defer h.Stop() // Always stop to clean up
Configuring
h.Name("myservice") // Set service name (default: "test")
h.Register(handler) // Set the handler
h.Start() // Start the service
Making Calls
// Simple call
err := h.Call("Handler.Method", &request, &response)
// With context
err := h.CallContext(ctx, "Handler.Method", &request, &response)
Assertions
// Check service is running
h.AssertServiceRunning()
// Check call succeeds
h.AssertCallSucceeds("Handler.Method", &req, &rsp)
// Check call fails
h.AssertCallFails("Handler.Method", &req, &rsp)
Advanced Access
// Get the client for custom calls
client := h.Client()
// Get the server
server := h.Server()
// Get the registry
reg := h.Registry()
Example: Testing a User Service
package users
import (
"context"
"testing"
"go-micro.dev/v6/test"
)
type UsersHandler struct {
users map[string]*User
}
type User struct {
ID string
Name string
}
type CreateRequest struct {
Name string
}
type CreateResponse struct {
User *User
}
func (h *UsersHandler) Create(ctx context.Context, req *CreateRequest, rsp *CreateResponse) error {
user := &User{ID: "123", Name: req.Name}
h.users[user.ID] = user
rsp.User = user
return nil
}
func TestUsersCreate(t *testing.T) {
h := test.NewHarness(t)
defer h.Stop()
handler := &UsersHandler{users: make(map[string]*User)}
h.Name("users").Register(handler)
h.Start()
var rsp CreateResponse
h.AssertCallSucceeds("UsersHandler.Create", &CreateRequest{Name: "Alice"}, &rsp)
if rsp.User == nil {
t.Fatal("user is nil")
}
if rsp.User.Name != "Alice" {
t.Errorf("expected Alice, got %s", rsp.User.Name)
}
// Verify the user was stored
if _, ok := handler.users["123"]; !ok {
t.Error("user not stored in handler")
}
}
Limitations
Due to go-micro’s global defaults, each harness should test one service. If you need to test service-to-service communication, consider:
- Integration tests - Run services as separate processes
- Mock clients - Mock the client calls to dependent services
- Contract tests - Test service interfaces separately
Tips
- Always defer Stop() - Ensures cleanup even if test fails
- Use meaningful names -
h.Name("users")makes logs clearer - Test edge cases - Use
AssertCallFailsfor error paths - Keep handlers simple - Complex handlers are harder to test
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.