Hey all, author here. I'm a bit late to the party but happy to answer any questions you have.<p>The main question seems to be: what's the difference between null implementations and mocks?<p>There's a practical answer to that question and a technical answer.<p>Practically speaking, the reason to use nullable infrastructure wrappers is that they enable sociable tests. A flaw of mock-based testing is that you only check that your system under test (SUT) <i>calls</i> its dependencies, but not that your code's expectations of its dependencies are correct. Sociable tests check that the SUT uses its dependencies <i>correctly.</i> This is valuable when refactoring, because it's easy to inadvertently introduce changes to behavior that break callers. Mock-based tests ("solitary tests") can't detect those errors.<p>Technically speaking, the nullable infrastructure wrappers convert your tests from interaction-based ("did I call the right methods") to state-based ("did my system return the correct results or make the appropriate state changes"). They do this by adding state inspection capabilities to production code, allowing you to assert on the state of the production code rather than asserting which methods were called. They also implement a tiny <i>hidden</i> stub to enable you to "turn off" interactions with the outside world.<p>My approach and mocks/spies are superficially similar, in that they both make use of test doubles (stubs, mocks, and spies are all test doubles) but they lead to significantly different testing approaches. Mocks/spies lead to interaction-based solitary tests, and nullable infrastructure leads to state-based sociable tests. I also find the tests are easier to write and read, and they're orders of magnitude faster¹ than using a mocking framework, too.<p>¹In a head-to-head comparison, nullable infrastructure ran 1,075,268 tests/sec, testdouble.js ran 12,210 tests/sec, and sinon.js ran 2,793 tests/sec. <a href="https://github.com/jamesshore/livestream/blob/2020-05-26-end/src/_comparisons_test.js" rel="nofollow">https://github.com/jamesshore/livestream/blob/2020-05-26-end...</a>
Enjoyed this much more than I thought I would<p>• Shows (almost) real-world examples to demonstrate the patterns<p>• Uses JavaScript, which is notoriously hard to test because of complex UI frameworks and difficult-to-mock APIs<p>• Set of patterns that refer to one another, providing mutual support<p>Would love to read more—any other resource along similar lines appreciated
<i>"Test-specific production code. Some code needed for the tests is written as tested production code, particularly for infrastructure classes. It requires extra time to write and adds noise to class APIs."</i><p>I don't see this much in real world code. Is there a space/niche that does this extensively? Does it raise a bunch of arguments about anti-patterns, etc?
Spoiler - expososing test data from the implementation: <a href="https://github.com/jamesshore/testing-without-mocks-example/blob/6e5e137e25933308b0146cc844aa01b561cd6986/src/command_line.js#L28" rel="nofollow">https://github.com/jamesshore/testing-without-mocks-example/...</a>
I felt too compelled to stick with existing design pattern theories and maintain a sort of persistent stubbornness with traditional xUnit style tests and TDD rather than follow the rabbit on this article.