tl;dr
- write a failing test from the outside in
- make it pass
- refactor towards good design
- take a break and repeat
TODO why?
- Write a single failing test at a time.
- Stick to the AAA pattern:
- Arrange the subject under test and all required inputs
- Act on the subject under test
- Assert the expected outputs
- If it is hard to test, its design probably needs improvement. Pay attention to your resistance. When writing the test is painful it is telling you something.
- Test from the outside in.
- Treat the subject under test a black box. We can only control its inputs and observe its outputs. If something is not observable it is irrelevant.
- Test the public interface of the unit under test.
- Do not test private methods.
- Use mocks for commands and stubs for queries.
- Favour pure functions over everything else. Pure functions are the testable by design. A function is pure if it always produces the same output for a given input and has no side-effects.
- If you're testing a Spring application's endpoints you will want to work these annotations.
- You must have seen it a test fail to trust it.
- Run all the tests in your test class together.
- End the day with a failing test. Tomorrow you will know exactly where to pick up.
Do the simplest thing to get the failing test to green.
TODO more here. but what?
"But when do write the real code?"
Refactor to improve the code. Since your details make no assumptions about the internals of your class you are free to refactor to your heart's content. Keep running the tests often to make sure you haven't left the green track.
Ask yourself these questions:
- Is it DRY?
- Does it have one and only one responsibility? In other words, there should be only one reason for a thing to change.
- Does everything inside change at the same rate?
- Does my class depend on things that change less often than itself does?
- Is there a clean separation between commands and queries - CQS?
Now you should probably take a break. Breaks are like water. You should have it before you need it. There are methods and tools to facilitate a sustainable pace. The most popular one is Pomodoro. Here's the timer I built, but there are many many others.
TODO discuss speed "it slows me down!"
Here a few seminal articles and talks to get you started:
- cyclomatic complexity (TODO)
- builders, fixtures, etc. patterns, constructor violates dry and encapsulation (TODO)
- SOLID Object-oriented design - Sandi Metz
- Mocks aren't stubs - Martin Fowler
- The Little Mocker - Robert C. Martin There is more:
- In general, listen to what Sandi Metz, J.B. Rainsberger and Mark Seemann are saying.
- Test-Driven Development by Example - Kent Beck
- Practical object-oriented design
- Learn to distinguish the different flavours of test doubles: dummy, fake, stub, spy and mock. Unlike common believe not everything is a mock. If you use Mockito check this.
- Familiarise yourself with the SOLID principles. This course is great.
- Learn your editor's features and shortcuts so your train of thought gets interrupted as little as possible.