Thanks to Logicroom for teaching me this.
With testing problems, the fix is rarely in the tests.
The fix is in the architecture.
As J.B. Rainsberger said, unit tests are the best.
With only a few integration tests at the edge.
But usually, the system is too coupled to have unit tests.
The tests write to the real filesystem, and run processes on the real operating system.
So the unit tests become integration or end to end tests.
The fix isn’t to improve the integration tests, as J.B. Rainsberger said.
Like using a better mocking library.
For example, in my VS Code extension, tests were slow.
They bootstrapped a real VS Code instance:
That’s because the code was very coupled to VS Code:
So it had to bootstrap VS Code to run the tests, which made tests almost impossible locally.
- I didn’t write many tests
- If they failed, I’d only see it in CI/CD
- They were integration, not unit tests
The fix wasn’t to bootstrap VS Code better.
Or to use a mocking library.
The fix was to decouple the extension from VS Code:
const spy = jest.fn(); fakeEditorGateway.editor.commands.registerCommand = spy;Code language: TypeScript (typescript)
Many times, dependency injection is the solution, though not with a framework.
Just a composition root.
In Clojure, it could be DI, or testing macros.
Now, tests run in 7 seconds:
But it’s not just faster.
It’s easier to write unit tests, so I write more.
They’re not flaky, so I believe them when they fail.
The right architecture makes tests easy.