Test doubles
Fixtures
TDD
Bob Martin defines test driven development as comprised of 3 rules:
- You are not allowed to write any prod code without writing a failing unit test. (Not compiling counts as failing.)
- You’re not allowed to write more of a unit test than is sufficient to fail. As soon as the test fails (or fails to compile), you must start writing prod code
- You are not allowed to write more prod code than is sufficient to pass the currently failing test.
In TDD you start with code that is very specific, and then as you add more tests, the code becomes more and more general. This is because with every new test, the test suite becomes more and more constrained.
Robert C. Martin - Advanced TDD: The Transformation Priority Premise
Unit testing helps us by
- Preventing regression
- Helps with design
Venkat Subramaniam: Succeeding with TDD: Pragmatic Techniques for effective mocking
-
Hard to test indicates poor design
- Mocks - can stand in for other objects
-
Stubs represent state, while mock represents behavior.
- Canary test - checks if the test env is setup
- eg. assert 1 == 1
Links
- Getting Testy - a series of articles on unit testing
Notes from TDD: By Example (Kent Beck)
Rules for TDD:
- Write new code only if an automated test has failed
- Eliminate duplication
Red-Green-Refactor
- Red: Write a failing test (might not even compile)
- Green: Make the test work
- Refactor: Eliminate all the duplication
TDD cycle:
- Quickly add a test
- Run all tests and see one fail
- make a little change
- run all tests and see them all succeed
- refactor to remove duplication
Strategies for getting from Red to Green:
- Fake It: Return a constant and gradually replace constants with variables until you have the real code
- Use Obvious Implementation: Type in the real implementation
- Triangulation: Only generalize code when a new test example demands a more
generalized solution
- useful when there isn’t an immediate path for refactoring
- add examples that change different axes of variability to make the solution clearer
When you have an objection to the design of the code
- translate that objection into a failing test
- get the code to compile with a stub implementation
- make the test work by typing in what seems like the right code
The red-green-refactor cycle can help you when you aren’t sure about the design
- use shorter steps when you aren’t confident about the overall design, and longer ones when you know where you’re going.
Three steps in a test:
- Arrange: create some objects
- Act: stimulate them
- Assert: check the results
Test coupling
- for performance, it might make sense to couple some tests - we could keep the Arrange stage constant, and vary the Act and Assert stages
- makes order of tests important, so changing the order could fail tests, or they could pass despite the code being incorrect
Testing Objects
Some quick notes from Sandi Metz’ talk, The Magic Tricks of Testing:
What to test:
- incoming messages
- assert on result for query messages
- assert on side effect for command messages
- message to self
- don’t test private commands
- don’t test private method
- verifying that the private method is called binds you to existing implementation
- discourages people from improving them
- messages to other objects
- don’t test outgoing query messages
- testing outgoing commands
- don’t assert on state of the other object
- inject a mock and verify that it receives the expected message