Grumpy Testing
Patterns
Chris Hartjes
PHP Australia Conference
April 15, 2016
Slide 2
Slide 2 text
No content
Slide 3
Slide 3 text
No content
Slide 4
Slide 4 text
Personal Opinions Ahead
Slide 5
Slide 5 text
This isn’t about shaming people
Slide 6
Slide 6 text
Testing has been around almost as
long as computer science itself
Slide 7
Slide 7 text
It pre-dates the rise of the internet
Slide 8
Slide 8 text
No content
Slide 9
Slide 9 text
It’s never too late to care about
automated tests for your application
Slide 10
Slide 10 text
So you’ve decided to write tests
❖ Is your code ready to test?
❖ Do you understand the testing tools?
❖ Do you understand some common testing patterns?
Slide 11
Slide 11 text
No content
Slide 12
Slide 12 text
What Do I Like To See?
❖ Dependency injection in use
❖ Small objects with few methods
❖ Bootstrapping that allows for easy overriding
Slide 13
Slide 13 text
No content
Slide 14
Slide 14 text
No content
Slide 15
Slide 15 text
Don’t Lose Control
❖ Dependencies you cannot control means tests you
cannot write
❖ Untested code can lead to weird bugs and unanticipated
behaviour
Slide 16
Slide 16 text
How To Control Dependencies
❖ Think of your program flow as “message passing”
❖ Refactor code to create required dependencies outside
of where they are used
❖ No shame in incremental refactoring towards testability
Slide 17
Slide 17 text
Dependency Management As “Message Passing”
❖ Architect your application so results and dependencies
flow through it
❖ Keep “side effects” to a minimum
❖ Give opportunities for tests to create doubles of
dependencies that need to be in specific states
Slide 18
Slide 18 text
No content
Slide 19
Slide 19 text
No content
Slide 20
Slide 20 text
Taming Side Effects
❖ in-memory databases using SQLite
❖ in-memory file systems using vfsStream
❖ “dependency overloading” using Mockery
Slide 21
Slide 21 text
In-Memory Databases
❖ Eliminates the side effect of modifying common
databases
❖ Much better control over initial data sets
Slide 22
Slide 22 text
No content
Slide 23
Slide 23 text
In-Memory Filesystems
❖ great for tests that need to read and/or write files
❖ no need to write code to clean up data after testing
Slide 24
Slide 24 text
No content
Slide 25
Slide 25 text
No content
Slide 26
Slide 26 text
No content
Slide 27
Slide 27 text
No content
Slide 28
Slide 28 text
Small objects with few methods
Slide 29
Slide 29 text
No content
Slide 30
Slide 30 text
“Using Test-Driven Development tends to result in
large numbers of objects with small numbers of
methods. Single responsibility principle in action!”
Slide 31
Slide 31 text
“Again, your tests suck because your code sucks.
No. Really.”
Slide 32
Slide 32 text
How To Detect Smelly Code
❖ Your tests require extensive setup steps
❖ Your code to set dependencies fills your editor screen
❖ It’s extremely difficult to tell if you’re getting the
expected results
Slide 33
Slide 33 text
Extensive Setup Steps
❖ Does your app have complicated bootstrapping?
❖ Does it rely on hard-coded values for configuration
options?
❖ How hard is it to swap out dependencies?
Slide 34
Slide 34 text
No content
Slide 35
Slide 35 text
No content
Slide 36
Slide 36 text
No content
Slide 37
Slide 37 text
For those counting along:
24 lines of setup
5 lines of tests
Slide 38
Slide 38 text
No content
Slide 39
Slide 39 text
For those counting along:
24 lines of setup
5 lines of tests
for 7 lines of code
Slide 40
Slide 40 text
Not all smelly code is wrong
Slide 41
Slide 41 text
Other things I see people doing
Slide 42
Slide 42 text
No content
Slide 43
Slide 43 text
No content
Slide 44
Slide 44 text
No content
Slide 45
Slide 45 text
“DO YOU NOT NOTICE HOW SIMILAR ALL
THESE TESTS ARE?!?.”
Slide 46
Slide 46 text
No content
Slide 47
Slide 47 text
“Just like duplicated code can be bad,
duplicated tests can be bad.”
Slide 48
Slide 48 text
What else do I see that I don’t like?
Slide 49
Slide 49 text
Avoid These
❖ conditional statements in your tests!
❖ loops in your tests!
❖ creating a test double of the thing you are testing just so
“the damn thing works”
Slide 50
Slide 50 text
“I’m sure I missed your favourite underused
technique that is actually just lazy.”
Slide 51
Slide 51 text
Not all smelly tests are wrong
Slide 52
Slide 52 text
They represent things to keep an
eye on going forward
Slide 53
Slide 53 text
Do You Understand The Tools?
❖ Do you know how to use the testing framework
❖ Do you know how test doubles work?
Slide 54
Slide 54 text
“The tools are hard to use”
Slide 55
Slide 55 text
The problem isn’t the tools
Slide 56
Slide 56 text
The problem is
unrealistic expectations
Slide 57
Slide 57 text
Tests are code you write
to prove your other code is right
Slide 58
Slide 58 text
Grumpy’s 4 Steps
To Test Mastery
Slide 59
Slide 59 text
Step The First:
Figure out your dependencies
Slide 60
Slide 60 text
Step The Second:
Figure out your expected outcome
Slide 61
Slide 61 text
Step The Third:
Write the test like everything already works
Slide 62
Slide 62 text
Step The Last:
Write code until the test passes
Slide 63
Slide 63 text
Want to learn more?
Search Github
Slide 64
Slide 64 text
Really.
Best place ever to find tests.
Slide 65
Slide 65 text
https://github.com/opencfp/opencfp
Slide 66
Slide 66 text
“There are too many examples of well-written tests
and clear instructions for people to claim
ignorance of how to write tests or use the tools to
execute them.”
Slide 67
Slide 67 text
No content
Slide 68
Slide 68 text
Handling The
Weird Stuff
Slide 69
Slide 69 text
Understanding Test Doubles
Slide 70
Slide 70 text
(people call them mocks)
Slide 71
Slide 71 text
Test Doubles
“Use them when you have a dependency that is
not under your control that needs to be in a
specific state.”
Slide 72
Slide 72 text
Creating doubles ONLY WHEN
REQUIRED is a good practice
Slide 73
Slide 73 text
So What Should We Double?
❖ database connections
❖ code that calls 3rd party API’s
❖ code that has side effects
Slide 74
Slide 74 text
Database Connections?
❖ does your unit test REALLY need to make sure the
database is working
❖ lets you control the expected responses in terms of
result sets or record ID’s
Slide 75
Slide 75 text
3rd Party API’s?
❖ API use could be restricted (rate-limited, sandboxed for
tests, pay-per-use)
❖ Again, are we in the business of testing their API or
testing our code?
Slide 76
Slide 76 text
“As an aside, consider the use of contract-style
tests as part of your integration test suite”
Slide 77
Slide 77 text
Weird Stuff To Test
❖ dependencies that you cannot inject without risky
refactoring
❖ getters and setters
❖ how to verify execution of specific code
Slide 78
Slide 78 text
No content
Slide 79
Slide 79 text
No content
Slide 80
Slide 80 text
Using “Monkey Patching”
❖ can override almost anything
❖ the overrides are globally available…
❖ …so annotate tests to run in separate process
Slide 81
Slide 81 text
No content
Slide 82
Slide 82 text
Mockery is awesome
Kahlan is awesome
Slide 83
Slide 83 text
Having to test that a non-public
method works is a testing smell
Slide 84
Slide 84 text
Having to test the contents and/or state
of a protected attribute is a test smell