This document discusses test-driven development (TDD) and unit testing. It introduces common unit testing tools and techniques like assertions, data providers, test doubles, and code katas. It emphasizes that TDD encourages building applications in a modular way using loosely coupled units like Legos. The document also covers dependency injection and different types of test doubles like stubs and mocks. Overall, it provides guidance on best practices for writing unit tests and using TDD to design code in an iterative way.
Learn To Test Like A Grumpy Programmer - 3 hour workshop
1. Learn To Test Like A
Grumpy Programmer
Chris Hartjes
SushinePHP 2017
2. Who is this guy
and why
should I listen?
• Long-time tester
• Beard conveys authority
• Twitter account is verified
• PHP dev since 1998
• Wants to help you get
better!
4. It’s Like Lego!
• TDD encourages creating applications by
combining units together like Legos
• Results in loosely-coupled modules
• Unit testing tools are no different
10. Code Kata I
• Code katas are small coding exercises with known
solutions
• Designed to turn certain programming practices
into “muscle memory”
• Concept taken from Asian martial arts
11. Code Kata I
• FizzBuzz!
• great exercise for covering programming basics
• easily tested
12. Code Kata I
• make sure you create a directory to do your
exercises in
• make sure you have Composer installed
• make sure you’ve installed PHPUnit using it
13. FizzBuzz
• Take a collection of integers only
• If the integer is divisible by 3, change it to ‘Fizz’
• If the integer is divisible by 5, change it to ‘Buzz’
• If the integer is divisible by 3 and 5, change it to
‘FizzBuzz’
• Otherwise do not change the value
14. Data Providers
• Reduce the number of tests you write
• Modify test data sets without modifying test
15. Data Providers
• Modify test method to accept parameters matching
the data you will provide
• Create a method that returns an array of arrays
containing data
16. Code Kata II
• Your turn to do some TDD!
• Create an object that turns Arabic numbers into
Roman Numerals
17. Code Kata II
• Use TDD to design your class
• Use data providers
• Get into writing code in an iterative way
18. Code Kata II
1 -> I 2 -> II 3 -> III 4 -> IV
5 -> V 6 -> VI 7 -> VII 8 -> VIII
9 -> IX 10 -> X 40 -> XL 50 -> L
19. Dependency Management
In Unit Tests
• Figure out your dependencies
• Figure out which ones need to be doubles
• “Inject” them for your code-under-test to use
21. Globally-available
Containers
• Best for legacy code where refactoring to injection
is difficult
• Can use $GLOBALS super global in a pinch
• Container / service locator usage very common
22. Constructor Injection
• Pass in dependencies at object creation
• Gets messy if many dependencies are required
• Can lead to __construct() doing too much work
23. Setter Injection
• “Less messy” than using constructors
• Refactoring to add get/set methods not overly
intrusive
• Allows overriding of internally-created
dependencies
24. Test Doubles
• Understanding them was the most difficult thing I
had to learn
• Makes you understand how critical putting
dependencies in specific states is
25. Types Of Test Doubles
• Classical definition is that there are five types
• Dummy objects, test stubs, test spies, test mocks,
test fakes
26. Types Of Test Doubles
• PHPUnit-compatible test double tools tend to only
use three
• Dummy objects, test stubs, test mocks
27. Dummy Object
• Stand-in for the real dependency
• Does not any functionality
• Only needs to ‘look like’ the real dependency
29. Stubs
• ‘Dummy object’ but with defined methods
• Methods don’t need to return anything
• Satisfies any calls to the dependency where the
response doesn’t matter
33. Test Doubles
Considered Harmful
• Be careful to not fall in love with test doubles
• Having to create too many of them exposes tightly-
coupled code
34. Test Doubles
Considered Harmful
• Use them when you have a dependency that is
difficult to use under normal circumstances
• Database connections and 3rd party API calls
come to mind
36. Code Kata III
• Use TDD to add a method called getAllActive()
• Uses fetchAll() to get back a data set that includes
id, email, and where is_active is set to 1 or 0
• Have at least 3 records, with 2 active
• You must manually filter out records in
getAllActive()
• return results as array with just ‘id’ and ‘email’