https://blog.nelhage.com/2016/03/design-for-testability/
blog-post-design-for-testability#good-fast-tests1 ... in order to really realize the benefits of good tests, you need to be able to run tests – or, at a minimum, the subset of tests covering your changes – quickly, in order to keep a fast development cycle. blog-post-design-for-testability#good-fast-tests1
blog-post-design-for-testability#what-is-a-unit1 There are a lot of religious arguments out there about the boundaries between "unit", "functional", "integration", and other sorts of tests; By "unit" tests here I mean tests that exercise some specific module or component of the code base with minimal dependencies on or invocation of other code in the application. blog-post-design-for-testability#what-is-a-unit1
blog-post-design-for-testability#write-code-with-unit-tests-in-mind1
Good unit tests don't happen by accident, however. It's very hard to have good unit tests without having good "units": Portions of code with narrow and well-defined interfaces, which can be tested at those interfaces.
The best way to have such logical units, which then permit excellent tests, which in turn permit rapid feedback cycles while maintaining a mature project, is just to do so directly: Write code with this end in mind.
blog-post-design-for-testability#write-code-with-unit-tests-in-mind1
blog-post-design-for-testability#unit-tests-scale-linearly1 More importantly, unit tests scale: In a codebase with mostly unit tests, test speed should scale linearly with application size. With more functional end-to-end tests, you risk scaling closer to quadratically, as each component requires tests that in turn incidentally exercise nearly every other component. blog-post-design-for-testability#unit-tests-scale-linearly1
blog-post-design-for-testability#pure-functions-table-test1 Pure functions over immutable data structures are delightfully easy to test: You can just create a table of (example input, expected output) pairs. They're generally also easy to fuzz with tools like QuickCheck, since the input is easy to describe. blog-post-design-for-testability#pure-functions-table-test1
blog-post-design-for-testability#io-and-computation-separation1 IO is, in general, harder to test than pure code. Testable systems therefore isolate it from the pure logic of the code, to allow them to be tested separately. blog-post-design-for-testability#io-and-computation-separation1