Front Matter
Dedications
Thanks!
About code examples
- Notes for C# users
- Notes for Java users
- Part 1: Just the basics
- Status: stable
Motivation – the first step to learning TDD
- What TDD feels like
- Let’s get it started!
The essential tools
- Test framework
- Mocking framework
- Anonymous values generator
- Summary
It’s not (only) a test
- When a test becomes something more
- Taking it to the software development land
- A Specification rather than a test suite
- The differences between executable and “traditional” specifications
Statement-first programming
- What’s the point of writing a specification after the fact?
- “Test-First” means seeing a failure
- “Test-After” often ends up as “Test-Never”
- “Test-After” often leads to design rework
- Summary
Practicing what we have already learned
- Let me tell you a story
- Act 1: The Car
- Act 2: The Customer’s Site
- Act 3: Test-Driven Development
- Epilogue
Sorting out the bits
How to start?
- Start with a good name
- Start by filling the GIVEN-WHEN-THEN structure with the obvious
- Start from the end
- Start by invoking a method if you have one
- Summary
How is TDD about analysis and what does “GIVEN-WHEN-THEN” mean?
- Is there a commonality between analysis and TDD?
- Gherkin
- TODO list… again!
What is the scope of a unit-level Statement in TDD?
- Scope and level
- On what level do we specify our software?
- What should be the functional scope of a single Statement?
- Failing to adhere to the three rules
- How many assertions do I need?
- Summary
Developing a TDD style and Constrained Non-Determinism
- A style?
- Principle: Tests As Specification
- First technique: Anonymous Input
- Second technique: Derived Values
- Third technique: Distinct Generated Values
- Fourth technique: Constant Specification
- Summary of the example
- Constrained non-determinism
- Summary
Specifying functional boundaries and conditions
- Sometimes, an anonymous value is not enough
- Exceptions to the rule
- Rules valid within boundaries
- Combination of boundaries – ranges
- Summary
Driving the implementation from Specification
- Type the obvious implementation
- Fake it (‘til you make it)
- Triangulate
- Summary
- Part 2: Object-Oriented World
- Status: pretty stable
- Teaching one thing at a time
On Object Composability
- Another task for Johnny and Benjamin
- A Quick Retrospective
Telling, not asking
- Contractors
- A Quick Retrospective
The need for mock objects
- Composability… again!
Why do we need composability?
- Pre-object-oriented approaches
- Object-oriented programming to the rescue!
- The power of composition
- Summary – are you still with me?
Web, messages and protocols
- So, again, what does it mean to compose objects?
- Alarms, again!
- Summary
Composing a web of objects
- Three important questions
- A preview of all three answers
When are objects composed?
How does a sender obtain a reference to a recipient (i.e. how connections are made)?
- Receive as a constructor parameter
- Receive inside a message (i.e. as a method parameter)
- Receive in response to a message (i.e. as a method return value)
- Receive as a registered observer
Where are objects composed?
- Composition Root
- Factories
- Summary
Interfaces
- Classes vs interfaces
- Events/callbacks vs interfaces – few words on roles
- Small interfaces
Protocols
- Protocols exist
- Protocol stability
- Craft messages to reflect the sender’s intention
- Model interactions after the problem domain
- Message recipients should be told what to do, instead of being asked for information
- Most of the getters should be removed, return values should be avoided
- Protocols should be small and abstract
- Summary
Classes
- Single Responsibility Principle
- Static recipients
- Summary
Object Composition as a Language
- More readable composition root
- Refactoring for readability
- Composition as a language
- The significance of a higher-level language
- Some advice
- Summary
Value Objects
- What is a value object?
- Example: money and names
Value object anatomy
- Class signature
- Hidden data
- Hidden constructor
- String conversion methods
- Equality members
- The return of investment
- Summary
Aspects of value objects design
- Immutability
- Handling of variability
- Special values
- Value types and Tell Don’t Ask
- Summary
- Part 3: TDD in Object-Oriented World
- Status: under development
Mock Objects as a testing tool
- A backing example
- Interfaces
- Protocols
- Roles
- Behaviors
- Filling in the roles
- Using a mock channel
- Mocks as yet another context
- Summary
Test-first using mock objects
- How to start? – with mock objects
- Responsibility and Responsibility
- Channel and DataDispatch one more time
- The first behavior
- Second behavior – specifying an error
- Summary
Test-driving at the input boundary
- Fixing the ticket office
- Initial objects
- Bootstrap
- Writing the first Statement
- Summary
Test-driving at the input boundary – a retrospective
- Outside-in development
- Workflow specification
- Data Transfer Objects and TDD
- Using a
ReservationInProgress - Interface discovery and the sources of abstractions
- Do I need all of this to do TDD?
- What’s next?
Test-driving object creation
Test-driving object creation – a retrospective
- Limits of creation specification
- Why specify object creation?
- What do we specify in the creational Statements?
- Value object creation
- Summary
Test-driving application logic
- Summary
Test-driving value objects
- Initial value object
- Value semantics
- Case-insensitive comparison
- Input validation
- Summary
Reaching the web of objects boundaries
- What time is it?
- Timers
- Threads
- Others
What’s inside the object?
- What are object’s peers?
- What are object’s internals?
- Examples of internals
- Summary
Design smells visible in the Specification
- Design smells’ catalog
- General description
- Flavors
THIS IS ALL I HAVE FOR NOW. WHAT FOLLOWS IS RAW, UNORDERED MATERIAL THAT’S NOT YET READY TO BE CONSUMED AS PART OF THIS TUTORIAL
Mock objects as a design tool
- Responsibility-Driven Design
Guidance of test smells
- Long Statements
- Lots of stubbing
- Specifying private members
Revisiting topics from chapter 1
- Constrained non-determinism in OO world
- Behavioral boundaries
- Triangulation
Maintainable mock-based Statements
- Setup and teardown
Refactoring mock code
- Part 4: Application architecture
On stable/architectural boundaries
Ports and adapters
- Physical separation of layers
What goes into application?
- Application and other layers
What goes into ports?
- Data transfer objects
- Ports are not a layer
- Part 5: TDD on application architecture level
Designing automation layer
- Adapting screenplay pattern
- Driver
- Actors
- Data builders
Further Reading
- Motivation – the first step to learning TDD
- The Essential Tools
- Value Objects