|
Wow! No wonder you find this tedious. Your gateway struct hopefully looks something like type Fooer interface{ ... }
type Barer interface{ ... }
type gateway struct{ f Fooer; b Barer; ... }
newGateway(f Fooer, b Barer, ...) (*gateway, error) { ... }
func (g *gateway) StartTransaction(...)
That is, a gateway is something that depends on other things, modeled as interfaces, and provides capabilities as methods. +--------------------+
| gateway |
| - f Fooer |
| - b Barer |
| - ... |
| |
input -------> StartTransaction -----> output
| ... |
+--------------------+
When you want to exercise this code, you want to construct an instance with mock/deterministic dependencies, so that you have predictable results when you apply input and receive output. That's the model: give input, assert output.But your linked code is kind of different! Each subtest varies not the input but the behavior of the mocked dependencies. I understand the point: you want to run through all the codepaths in the gateway method. But is that worth testing? Do the tests meaningfully reduce risk? I dunno. It's not obvious to me that they do. The use of gomock is also a big smell. Generating mocks kind of defeats the purpose of using them. I would definitely write a bespoke client: type mockClient struct {
StartTransaction func(...) (xxx.Transaction, error)
Upsert func(...) (xxx.Result, error)
AbortTransavtion func(...) (xxx.Xxx, error)
}
Then each test case is simpler to express as for _, tc := range []struct{
name string
client *mockClient
input UpdateConfigRequest
startRes xxx.Transaction
startErr error
upsertRes xxx.Result
upsertErr error
res xxx.UpdateConfigResponse
err error
} {
{
name: "success",
client: &mockClient{StartTransaction: good, ...},
startRes: ...,
upsertRes: ...,
res: ...,
},
{
name: "bad start",
client: &mockClient{StartTransaction: bad, ...},
startErr: ...,
},
{
name: "bad upsert",
client: &mockClient{StartTransaction: good, Upsert: bad, ...},
startRes: ...,
upsertErr: ...,
},
...
} {
t.Run(tc.name, func(t *testing.T) {
g := newGateway{tc.client}
output := g.StartTransaction(tc.input)
// asserts
})
}
|