One reasonable way to get from a few slow-running end-to-end tests to some strategic unit testing is to do the following whenever you encounter a bug:
[...]
Another suggestion: apply the Saff Squeeze. Think "debugging with automated tests".
Start with a failing test.
1. Inline the action of the test: that's the central function that you invoke to make the test _do_ something.
2. Make invisible things visible (private -> public in many languages).
3. Prune away dead code, such as the branches of an `if` statement that this test's input won't run. Maybe unroll a loop.
4. Add assertions to check intermediate results, especially the conditions of `if` statements or the stopping conditions of loops. Do this until you add an assertion that fails.
5. After you add a new failing assertion, delete the rest of the test; it won't execute, anyway.
Now you have a smaller test that fails for the same reason as the original test. Commit. Maybe now it's obvious what caused the defect. Yes? Fix it. No? Repeat the process.
This is one way to uncover smaller unit tests that would have helped you. Over time, you'll get to know which kinds of smaller unit tests you want to practise writing.
--
J. B. (Joe) Rainsberger :: ?:: ::
--
J. B. (Joe) Rainsberger :: :: ::
Teaching evolutionary design and TDD since 2002