Apr 25 2020
Better Coverage with DI
Global variables actually prevent us from increasing coverage.
Compare functions that use global variables with pure input/output functions. It is very easy to alter the runtime path in a pure function: simply alter the input. When testing globals, altering runtime paths becomes much more difficult. There is too much “magic” happening inside of the function.
Likewise, consider a runtime environment being different from its test environment. For example, a node environment could be testing code for a browser. What happens when node attempts to access variables only found in a browser? Now we get defective tests!
Let’s reference a code snippet from the open source project validate.js.
This refactor is more of a thought experiement than anything. This is not terribly bad code. However it is difficult to get 100% code coverage:
- There is a reference to a global variable.
- We cannot assert the non-existance of a global variable (or any variable for that matter).
The first issue is a fairly trivial fix. It’s common to reach for dependency injection. However, the second issue is a little more nefarious.
What if a user should be warned, but does not have the
These attempts to cry out to the user would be silenced.
If the intent is to warn the user, it’s not much of a stretch to throw an error.
Now we can be sure that our concerns meet the user. If they have console.warn, we can give them our custom error. Otherwise we can at least tell them to change environments.
Now we can go after the global variable issue.
This gives sufficient access to complete branch coverage.
In order to verify branch coverage, we can inject a spy.
The spy asserts the
Beyond this, I would only have one other recommendation.
It would make more sense to rename the imported
warn function to something like
This name change is necessitated from the introduction of DI.
What did we “unlock” as a result of the refactor?
- console.warn does not execute when running tests: keeping the logs clean
- No log side-effects in our test runner
- 100% coverage
- Ability to provide different loggers.
- Elimination of global variables