When writing a Go test, don’t just assert that an error occurred - assert that the error you have is the one you expect.
I’ve seen a bunch of test code recently that simply asserted that an error happened:
g.Expect(err).To(HaveOccurred())
(I’m using gomega for my assertion library here, but I’ve seen this pattern in tests using testify as well as in tests using no assertion library at all.)
The problem with this is that the test will pass if any error happens.
The purpose of a test is to fail if the unexpected happens.
If your code expects the operation to fail with the error “customer is not eligible for Gold VIP programme” and now it’s failing with the error “syntax error in query string”, isn’t that something you want to know?
A related problem comes with tests that assert an error returns exactly a specified string:
g.Expect(err.Error()).To(Equal("compiling editor context expression: error parsing regexp: missing closing ]: `[A-Z`"))
These tests are brittle because any change to the error message at all will break the test, including fixes to typos, spelling corrections, even punctuation changes.
Instead, assert that the error contains the information you expect, so that minor changes don’t break your test for trivial reasons.
For example, here’s an assertion from crddoc:
g.Expect(err).To(HaveOccurred())
g.Expect(err).To(MatchError(ContainSubstring("does not match")))
g.Expect(err).To(MatchError(ContainSubstring("alertsmanagement.azure.com")))
g.Expect(err).To(MatchError(ContainSubstring("network.azure.com")))
Nitpickers corner: I’m well aware of the guideline that each test should have a single assert. I follow this by asserting a single fact - here, that the error is the one we expect. The fact that this logical assert takes four physical asserts is an implementation detail. Though it’s worth noting that the first assert isn’t strictly necessary as MatchError()
will fail if no error is present; I keep it for clarity.
Tip: Write robust tests by asserting that you get the error you expect, and not some other error instead. Make these asserts resilient against trivial changes by checking the error contains the right information, not that it exactly matches a given string.