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




















