- The problem with TDD.
- A practical approach to TDD.
- Start with an inside-out approach and learn what we need along the way.
- Transition to an outside-in approach.
- Software consultant.
- Obsessed with testing.
- Plain Rails app.
- Learn by building a taco order app.
- Going to work through a series of exercises.
- Might work through the examples together if time becomes a problem.
- Exercise branch and solution branch for each exercise. e.g.
exercise_1
andsolution_1
. - Open the solution and keep it for reference if you get stuck.
- Run
bundle exec guard
to get a test watcher going.
- The process of using tests to drive the development of your system.
- Red, green, refactor.
- Benefits: confidence and feedback loop. (Not design IMO.)
- Red, green, refactor.
- Confidence and feedback loop.
- Don't always have to take such small baby steps.
- Inside-out vs outside-in.
- Inside-out: Unit -> Integration -> Feature.
- Outside-in: Feature -> Integration -> Unit.
- Unit test: Tests a single unit.
- Solitary vs sociable (Martin Fowler).
- Test pyramid.
- Mocking.
- Using stubs instead of test doubles.
- Focusing a test.
- Solitary vs sociable unit tests.
- Test pyramid.
- Mocking.
- The problem with mocking / stubbing / test doubles.
- Mocking
- Benefits: Defect localization, speed, setup.
- Cons: False reality, brittle tests, refactoring.
- Whitebox vs blackbox.
- Blackbox > whitebox.
- The more your tests resemble your user, the more confidence they can give you. ~ Kent Dodds.
- What makes practical unit tests?
- Unit tests that don't use mocking / test doubles.
- Exceptions: Interacting with 3rd party APIs or things like that.
- Benefits: Increased confidence and feedback loop.
- Robust tests > defect localization.
- Improved our confidence by making our tests more realistic.
- Avoid mocking if at all possible.
- Robust tests > defect localization.
- Integration test: Test that exercise the functionality of two or more units together.
- Benefits: Increased confidence over a unit test.
- My opinion: Should be the majority of your test suite.
- "Write tests. Not too many. Mostly integration." ~ Guillermo Rauch
- Definition of an integration test.
- Focus most of your testing effort on integration tests.
- Feature test: Tests the application like your user.
- Benefits: Confidence.
- Drawbacks: Slow.
- Feature tests test the app like your user.
- Gives us the most confidence.
- Slow to run.
- Finished the inside-out approach.
- Going to look at some tradeoffs.
- Unit tests are a form of white box testing.
- Inside-out without mocking can be good, but it has some tradeoffs.
- Not as much confidence.
- Might have to change your tests when refactoring.
- Step back and think: What do we really care about when building an application?
- That it works the way the user expects it to.
- Green tests don't matter if the application doesn't work for the user.
- The goal: Test things like the user.
- Outside-in: Feature -> Integration -> Unit.
- My approach: Feature -> Integration -> (Maybe) Unit.
- Would be amazing if we could use feature tests to drive development.
- But Javascript.
- Solution: Write feature tests for confidence and use integration tests to flesh out functionality for a quick feedback loop.
- Goal: Test things like our users.
- Would be awesome if we could use feature tests. But Javascript.
- Write feature tests and then use integration tests for a quick feedback loop.
- Practical approach to TDD, from my experience.
- When writing tests at a higher level, building API for your tests is important.
- Otherwise, you end up with a lot of duplication.
- Once you build an API, building tests is like building with legos.
- Factories are one of the best ways to do that.
- Factory: Encapsulates knowledge of how to setup different objects in your system.
- Factory Bot.
- Having an API for your tests is important when testing at a higher level to avoid duplication.
- Once you have an API, it's like legos.
- Factories are usually low hanging fruit here.
- Factories encapsulate knowledge of how to setup different objects in your system.
- Factory Bot.
- The hardtest part of this approach (after speed): Dealing with combinatorial explosion.
- Combinatorial explosion: Rapid growth of the complexity of a problem.
- i.e.: An explosion in the number of scenarios that we have to account for.
- One of the arguments for mocking and inside-out TDD.
- My experience: Trying to cover every edge case and scenario isn't practical.
- Instead: Focus on the most likely cases and add tests as issues come up.
- Locking everything down with mocks and an inside-out approach LIKE % "Lord Business trying to glue everything down."
- Can't move or change anything. Refactoring is difficult.
- Leads to TDD burnout.
- Solution: Use tests that are as high level as possible and give you a quick feedback loop.
- Combinatorial explosion.
- One of the biggest arguments for mockist / inside-out TDD.
- Not practical.
- Like Lord Business from the Lego movie. Can't move or change anything.
- Makes refactoring difficult.
- Leads to TDD burnout.
- Solution: Use tests that are as high level as possible and give you a quick feedback loop.
- Help others see the value of TDD.
- Start with integration tests.
- If that's all you can get, it will be a huge win.
- Start small. Have a goal of adding or updating 1 test with each PR.
- If you can get more, add feature tests. Big confidence.
- Going to start publishing resources to help out with this.
- Staying away from mocking / test doubles makes your tests far more practical.
- You can use inside-out or outside-in. I recommend outside-in.
- Write feature tests and then use integration tests to flesh out the functionality.
- Build an API for your tests.