Scaling Go Testing with Contract and Scenario Mocks
Key topics
The debate around testing in Go is heating up, with some developers expressing frustration with the common practice of relying heavily on mocks and interfaces. One commenter, SPascareli13, sparked a lively discussion by voicing their dislike for this approach, which they felt led to brittle tests that only verified implementation details. However, others, like esafak and tonyhb, countered that testing interfaces can be a valid strategy, as it allows for implementation changes without affecting tests. The author, preetamjinka, chimed in to acknowledge the concerns and clarify their own approach, which involves using a mix of contract and scenario mocks to scale Go testing.
Snapshot generated from the HN discussion
Discussion Activity
Active discussionFirst comment
6d
Peak period
16
132-144h
Avg / period
13.5
Based on 27 loaded comments
Key moments
- 01Story posted
Dec 18, 2025 at 1:09 PM EST
22 days ago
Step 01 - 02First comment
Dec 24, 2025 at 8:41 AM EST
6d after posting
Step 02 - 03Peak activity
16 comments in 132-144h
Hottest window of the conversation
Step 03 - 04Latest activity
Dec 24, 2025 at 5:16 PM EST
16 days ago
Step 04
Generating AI Summary...
Analyzing up to 500 comments to identify key contributors and discussion patterns
Want the full context?
Jump to the original sources
Read the primary article or dive into the live Hacker News thread when you're ready.
This excludes a lot of cases, like just a simple postgres where reads are done from a replica.
Another way of looking at this advice is that every time there’s a mock there needs to be a test that shows that the real code can be used in the same way that the mock is used.
I find this types of tests incredibly coupled with the implementation, since any chance require you to chance your interfaces + mocks + tests, also very brittle and many times it ends up not even testing the thing that actually matters.
I try to make integration test whenever possible now, even if they are costly I find that the flexibility of being able to change my implementation and not break a thousand tests for no reason much better to work with.
The pain comes when system B changes. Oftentimes you can’t even make a benign change (like renaming a function) without updating a million tests.
Unfortunately there is no consistency in the nomenclature used around testing. Testing is, after all, the least understood aspect of computer science. However, the dictionary suggests that a "mock" is something that is not authentic, but does not deceive (i.e. behaves like the real thing). That is what I consider a "mock", but I'm gathering that is what you call a "fake".
> checking that query.Execute was called with the correct arguments.
I agree that that sounds ridiculous and I am not sure why anyone would ever do such a thing. I'm not sure that even needs a name.
If you are changing the interface, though, that would mean a contract change. And if you're changing the contract, surely you wouldn't be able to even use the old tests?
This isn't really a go problem at all. Any contract change means changing tests.
> only ever use an interface, never the real implementation + mockgen the mocks based on this interface + use the mocks to assert that a function is called, with exactly this parameters and in this exact order.
is not ideal, and that's what we don't do. We test the real implementation, then that becomes the contract. We assume the contract when we write the mocks.
Same I have zero confidence in these tests and the article even states that the tests will fail if a contract for a external service/system changes
These tests won't detect if a dependency has changed, but that's not what they're meant for. You want infrastructure to monitor that as well.
The fundamental point of tests should be to check that your assumptions about a system's behavior hold true over time. If your tests break that is a good thing. Your tests breaking should mean that your users will have a degraded experience at best if you try to deploy your changes. If your tests break for any other reason then what the hell are they even doing?
When you mock a CRM client to return one account, you're assuming it always returns one account, that IDs have a particular format, that there's no pagination, that all fields are populated. Each assumption is a place where production could behave differently whilst your tests stay green
Your contract tests use cached JSON fixtures. Salesforce changes a field type, your contract test still passes (old fixture), your mocks return the wrong type, production breaks. You've now got three test layers (contract, mock scenarios, E2E) where two can lie to you. All your contract and mock tests won't save you. Production will still go down
I have zero confidence in these types of tests. Integration tests and E2E tests against real infrastructure give me actual confidence. They're slower, but they tell you the truth. Want to test rate limiting? Use real rate limits. Want to test missing data? Delete the data.
Slow tests that tell the truth beat fast tests that lie. That said, fast tests are valuable for developer productivity. The trade-off is whether you want speed or confidence
If you do not trust Salesforce to change the contract you have with them (without proper notice, at least), can you really trust using their service at all?
That said, if you do find a need to write tests for them for whatever reason, you can do so in an independent test suite. You don't have to — nor is it beneficial to — ensure their contract is upheld through osmosis.
https://pactflow.io/
I've also started to appreciate the idea of contract tests more and more, especially as our system scales. It kind of feels like setting a solid foundation before building on top. I haven’t used Pact or anything similar yet, but it’s been on my mind.
I wonder if there’s a way to combine the benefits of mocks and contracts more seamlessly, maybe some hybrid approach where you can get the speed of mocks but with the assurance of contracts... What do you think?
Yes, it takes longer to run your tests. So be it.
If you have SQL scattered all over the place... Well, just don't do that. Even outside of testing that is not a pleasant place to end up.
We also hack mocks/stubs/spies in our unit tests. Those are great for producing hard-to-trigger edge cases. But contract testing? The contract is the data flow.
We also have mocks. It’s not one way or the other. This post is talking about the mocking side of things.
And then it should be part of that service's test suite, to verify it's own mock.
You update your service? Then you must update the mock.
I guess that's more of a fake, but the naming doesn't matter as much as the behavior.