liveBook · Manning

Mocking

As explained in gRPC Microservices in Go

A mock is a test double that implements an interface and provides programmable responses for controlling a dependency's behavior.

A mock replaces a dependency during a test so the system under test can run without that dependency’s real internals. In an Order service, mocked database and Payment service calls keep setup small and let a test choose the response to each call. Starting a real MySQL database with test containers is another option, but mocking gives faster feedback when the goal is to test Order service behavior. section 7.2.2 section 7.2.3

Mock an interface rather than a concrete implementation. In a hexagonal design, the Order service already depends on DBPort and PaymentPort, so tests can supply replacements without changing application code. section 7.2.3

To test PlaceOrder:

  • Implement each port with a mock struct. Embed testify’s mock.Mock and give its methods the signatures required by the port; use Called to retrieve configured return values. section 7.2.4
  • Configure Charge and Save responses with On(...).Return(...), then pass the mocks to the application. Returning nil from both calls tests successful order placement. section 7.2.4
  • Change one configured response to test a failure branch. A Save error should reach the caller; a Charge error should produce the order-creation error and a payment field violation. section 7.2.4
type mockedPayment struct {
    mock.Mock                         #1
}
 
func (p *mockedPayment) Charge(order *domain.Order) error {
    args := p.Called(order)           #2
    return args.Error(0)              #3
}
 
type mockedDb struct {
    mock.Mock
}
 
func (d *mockedDb) Save(order *domain.Order) error {
    args := d.Called(order)
    return args.Error(0)
}
 
func (d *mockedDb) Get(id string) (domain.Order, error) {
    args := d.Called(id)
    return args.Get(0).(domain.Order), args.Error(1)
}

The payment and database replacements implement their ports by forwarding calls to mock.Mock and returning the configured results. section 7.2.4

A failed database save

Configure db.Save to return “connection error,” call PlaceOrder, and assert that the returned error has that message. This checks the application’s error path without causing a real database failure. section 7.2.4

When many interfaces need mocks, mockery can generate mock files for them. Regenerate those files when an interface changes, then configure their behavior in tests as before. Generated mocks remove the need to write each method’s argument and return-value handling by hand. section 7.2.5

How gRPC Microservices in Go covers it

How deep it goes
Shows manual port implementations, response configuration, and success and error-path assertions; also introduces generated mocks without examining library internals.
Examples
Uses PlaceOrder tests with successful database and payment calls, a failed Save, and a failed Charge with a payment validation error.
What it assumes
Assumes Go interfaces and existing database and payment ports; teaches how to implement their mocks and configure test responses.
What you can do after
Build it from scratch with testify/mock, or apply it via mockery, to control Order service dependencies in unit tests.
How it connects
Connects unit testing to hexagonal architecture, interfaces, test containers, and service-boundary error handling.

Also explained in

Compare how 21 books explain mocking →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of gRPC Microservices in Go. The section links point to the parts of the book it draws on.