A Go developer using gomock faces inconsistent behavior when running subtests that rely on gomock.InOrder. They have multiple test cases defined in a map and use subtests (t.Run) to execute each one. Expected mock calls are defined using gomock.InOrder, but the tests sometimes fail with an error indicating that a prerequisite call wasn’t satisfied. Upon investigation, they noticed that Go doesn’t guarantee iteration order for maps, so subtests don’t always execute in the same sequence (test1, test2, test3). When debugging, the tests pass, but when running normally, they fail due to non-deterministic order. The developer is seeking a reliable way to ensure subtests and mock expectations run in a deterministic sequence when using gomock.InOrder.
Ah, I see where the issue is coming from! This is one of those classic gotchas with Go maps. Since Go doesn’t guarantee iteration order for maps, the subtests that rely on gomock.InOrder may run in different sequences each time, causing those intermittent failures you’re seeing. The easiest fix here is to ensure that your subtests run in a deterministic order by sorting your map keys before running them.
Here’s a quick fix you can implement:
testCases := map[string]struct{}{ /* ... */ }
keys := make([]string, 0, len(testCases))
for k := range testCases {
keys = append(keys, k)
}
sort.Strings(keys)
for _, name := range keys {
t.Run(name, func(t *testing.T) {
// test logic here
})
}
By sorting the keys, you can guarantee that your subtests will execute in a predictable order, and this will ensure that your gomock.InOrder expectations are satisfied every time.
Exactly! I ran into the same issue a while back. The thing with gomock.InOrder is that it expects a strict sequence of mock calls, and since Go’s maps are inherently unordered, without sorting, the subtests can run in different sequences, which leads to flaky tests.
Just like Charity said, sorting your test keys or, alternatively, using a slice of test cases rather than a map is your safest bet to keep the call order predictable. This small step makes sure that gomock.InOrder behaves as expected, reducing that order-related flakiness.
I’ve also come across this issue before, and I’ve found that isolating each subtest with its own gomock.Controller instance can be a neat trick when the subtests are independent. This way, the mock expectations set with gomock.InOrder are applied only within that subtest’s scope, making them less likely to conflict with each other.
When you combine this approach with sorting your keys (as we discussed earlier), you’re not just ensuring a deterministic test order, but you’re also creating isolated, clean tests. It’s a win-win for avoiding flaky tests and ensuring your expectations are always met.