SlideShare a Scribd company logo
Why Your Test Suite Sucks
(and what you can do about it)
by Ciaran McNulty at PHPCon Poland 2015
It’s not working for me
===
TDD must suck1
1
BIT.LY/1LEF0GI & BIT.LY/1SLFGTQ
The problem is not TDD
The problem is your suite
Value = Benefits - Costs
Suites suck when you aren’t ge)ng
all the benefits of TDD
Suites suck when the tests are hard
to maintain
Reason 1:
You don't have a test suite
The Evolu*on of a TDD Team
Maturity model
• Manual tes&ng
• Automated tes&ng
• Test-first development
• Test-driven development
Manual tes*ng
• Design an implementa+on
• Implement that design
• Manually test
Growing from Manual to Automated
• “When we make changes, it breaks things!”
• “We spend a lot of /me on manual tes:ng”
• “Bugs keep making it into produc:on”
Enabled by:
- Tutorials, training
- Team policies
Automated tes+ng
• Design an implementa+on
• Implement that design
• Write tests to verify it
Growing from Automated to Test-first
• “It’s a pain having to write tests once I’m done”
• “My test suite is bri'le”
• “Maintaining the suite is hard”
• ”TDD Doesn’t Work!”
Supported by:
- Coaching, pairing
- Leadership
Test-first development
• Design an implementa+on
• Write tests to verify that implementa+on
• Implement that design
Growing from Test-first to Test-driven
• “Test suite is s"ll bri,le”
• “Maintaining the suite is s"ll hard”
• ”TDD Doesn’t Work!”
Supported by:
- Prac1ce
Test-driven development
• Write tests that describe behaviour
• Implement a system that has that behaviour
Problems:
- “I don’t know what to do with all this spare 'me!”
- “Where should we keep this extra money?”
Reason 2:
You are tes*ng implementa*on
Problem: Mocking Queries
• A query is a method that returns a value without side effects
• We shouldn’t care how many 4mes (if any) a query is called
• Specifying that detail makes change harder
function testItGreetsPeopleByName()
{
$user = $this->getMock('User');
$user->expects($this->once())
->method('getName')
->willReturn('Ciaran');
$greeting = $this->greeter->greet($user);
$this->assertEquals('Hello, Ciaran!', $greeting);
}
function testItGreetsPeopleByName()
{
$user = $this->getMock('User');
$user->method('getName')
->willReturn('Ciaran');
$greeting = $this->greeter->greet($user);
$this->assertEquals('Hello, Ciaran!', $greeting);
}
Don’t mock queries, just use stubs
Do you really care how many /mes it's called?
Problem: Tes,ng the sequence of calls
• Most of the *me we don’t care what order calls are made in
• Tes*ng the sequence makes it hard to change
public function testBasketTotals()
{
$priceList = $this->getMock('PriceList');
$priceList->expect($this->at(0))
->method('getPrices')
->willReturn(120);
$priceList->expect($this->at(1))
->method('getPrices')
->willReturn(200);
$this->basket->add('Milk', 'Bread');
$total = $this->basket->calculateTotal();
$this->assertEqual(320, $total);
}
public function testBasketTotals()
{
$priceList = $this->getMock('PriceList');
$priceList->method('getPrices')
->will($this->returnValueMap([
['Milk', 120],
['Bread', 200]
]));
$this->basket->add('Milk', 'Bread');
$total = $this->basket->calculateTotal();
$this->assertEqual(320, $total);
}
Test behaviour you care about,
don’t test implementa/on
PROTIP: The best way to do this is to not
have an implementa3on yet
Reason 3:
Because your design sucks
Problem: Too many Doubles
• It is painful to have to double lots of objects in your test
• It is a signal your object has too many dependencies
public function setUp()
{
$chargerules = $this->getMock('ChargeRules');
$chargetypes = $this->getMock('ChargeTypes');
$notifier = $this->getMockBuilder('Notifier')
->disableOriginalConstructor()->getMock();
$this->processor = new InvoiceProcessor(
$chargerules, $chargetypes, $notifier
);
}
class InvoiceProcessor
{
public function __construct(
ChargeRules $chargeRules,
ChargeTypes $chargeTypes,
Notifier $notifier
)
{
$this->chargeRules = $chargeRules;
$this->chargeTypes = $chargeTypes;
$this->notifier = $notifier;
}
// …
Too many doubles in your test mean
your class has too many
dependencies
Problem: Stubs returning stubs
• A related painful issue is stubs returning a stubs
• It is a signal our object does not have the right dependencies
public function testItNotifiesTheUser()
{
$user = $this->getMock(User::class);
$contact = $this->getMock(Contact::class);
$email = $this->getMock(Email::class);
$emailer = $this->getMock(Emailer::class);
$user->method('getContact')->willReturn($contact);
$contact->method('getEmail')->willReturn($email);
$emailer->expects($this->once)
->method('sendTo')
->with($this->equalTo($email));
(new Notifier($emailer))->notify($user);
}
class Notifier
{
public function __construct(Emailer $emailer)
{
// …
}
public function notify(User $user)
{
$email = $user->getContact()->getEmail()
$this->emailer->sendTo($email);
}
}
class Notifier
{
public function __construct(Emailer $emailer)
{
// …
}
public function notify(User $user)
{
$this->emailer->sendTo($user);
}
}
class Notifier
{
public function __construct(Emailer $emailer)
{
// …
}
public function notify(Email $email)
{
$this->emailer->sendTo($email);
}
}
public function testItNotifiesTheUser()
{
$email = $this->getMock(Email::class);
$emailer = $this->getMock(Emailer::class);
$emailer->expects($this->once)
->method('sendTo')
->with($this->equalTo($email));
(new Notifier($emailer))->notify($user);
}
Stubs returning stubs indicate
dependencies are not correctly
defined
Problem: Par+ally doubling the object under
test
• A common ques*on is “how can I mock methods on the SUT?”
• Easy to do in some tools, impossible in others
• It is a signal our object has too many responsibili*es
class Form
{
public function handle($data)
{
if ($this->validate($data)) {
return 'Valid';
}
return 'Invalid';
}
protected function validate($data)
{
// do something complex
}
}
function testItOutputsMessageOnValidData()
{
$form = $this->getMock('Form', ['validate']);
$form->method('validate')->willReturn(true);
$result = $form->handle([]);
$this->assertSame('Valid', $result);
}
class Form
{
protected function __construct(Validator $validator)
{
// …
}
public function handle($data)
{
if ($this->validator->validate($data)) {
return 'Valid';
}
return 'Invalid';
}
}
function testItOutputsMessageOnValidData()
{
$validator = $this->getMock(‘Validator’);
$validator->method('validate')->willReturn(true);
$form = new Form($validator);
$result = $form->handle([]);
$this->assertSame('Valid', $result);
}
If you want to mock part of the SUT
it means you should really have
more than one object
How to be a be)er so,ware designer:
• Stage 1: Think about your code before you write it
• Stage 2: Write down those thoughts
• Stage 3: Write down those thoughts as code
How long will it take without TDD?
• 1 hour thinking about how it should work
• 30 mins Implemen6ng it
• 30 mins Checking it works
How long will it take with TDD?
• 1 hour Thinking in code about how it should work
• 30 mins Implemen8ng it
• 1 min Checking it works
Use your test suite as a way to
reason about the code
Customers should not dictate your
design process
Reason 4:
You are unit tes,ng across domain
boundaries
Problem: Tes,ng 3rd party code
• When we extend a library or framework we use other people’s
code
• To test our code we end up tes.ng their code too
• This :me is wasted – we should trust their code works
class UserRepository extends FrameworkRepository
{
public function findByEmail($email)
{
$this->find(['email' => $email]);
}
}
public function testItFindsTheUserByEmail()
{
$db = $this->getMock(FrameworkDatabaseConnection::class);
$schemaCreator = $this->getMock(FrameworkSchemaCreator::class);
$schema = $this->getMock(FrameworkSchema::class);
$schemaCreator->method('getSchema')->willReturn($schema);
$schema->method('getMappings')->willReturn(['email'=>'email']);
$db->method('query')->willReturn(['email'=>'bob@example.com');
$repo = new UserRepository($db, $schemaCreator);
$user = $repo->findByEmail('bob@example.com');
$this->assertType(User::class, $user);
}
class UserRepository
{
private $repository;
public function __construct(FrameworkRepository $repository)
{
$this->repository = $repository;
}
public function findByEmail($email)
{
return $this->repository->find(['email' => $email]);
}
}
public function testItFindsTheUserByEmail()
{
$fwRepo = $this->getMock(FrameworkRepository::class);
$user = $this->getMock(User::class);
$repository = new UserRepository($fwRepo);
$fwRepo->method('find')
->with(['email' => 'bob@example.com')
->willReturn($user);
$actualUser = $repository->findByEmail('bob@example.com');
$this->assertEqual($user, $actualUser);
}
When you extend third party code,
you take responsibility for its
design decisions
Favour composi'on over
inheritance
Problem: Doubling 3rd party code
• Test Doubles (Mocks, Stubs, Fakes) are used to test
communica(on between objects
• Tes:ng against a Double of a 3rd party object does not give us
confidence that we have described the communica:on correctly
public function testItUploadsValidDataToTheCloud()
{
$validator = $this->getMock(FileValidator::class);
$client = $this->getMock(CloudApi::class);
$file = $this->getMock(File::class);
$validator->method('validate')
->with($this->equalTo($file))
->willReturn(true);
$validator->expects($this->once())->method('startUpload');
$client->expects($this->once())->method('uploadData');
$client->expects($this->once())
->method('uploadSuccessful')
->willReturn(true);
(new FileHandler($client, $validator))->process($file);
}
Coupled architecture
Coupled architecture
Layered architecture
Tes$ng layered architecture
public function testItUploadsValidDataToTheCloud()
{
$fileStore = $this->getMock(FileStore::class);
$file = $this->getMock(File::class);
$validator->method('validate')
->with($this->equalTo($file))
->willReturn(true);
(new FileHandler($fileStore, $validator))->process($file);
}
Tes$ng layered architecture
class CloudFilestoreTest extends PHPUnit_Framework_TestCase
{
/** @group integration */
function testItStoresFiles()
{
$testCredentials = …
$file = new File(…);
$apiClient = new CloudApi($testCredentials);
$filestore = new CloudFileStore($apiClient);
$filestore->store($file);
$this->assertTrue($apiClient->fileExists(…));
}
}
Tes$ng layered architecture
Don’t test other people’s code
You don't know how it's supposed to behave
Don’t test how you talk to other
people’s code
You don't know how it's supposed to respond
Pu#ng it all together
• Use TDD to drive development
• Use TDD to replace exis1ng prac1ces, not as a new extra task
Pu#ng it all together
Don’t ignore tests that suck, improve them:
• Is the test too !ed to implementa!on?
• Does the design of the code need to improve?
• Are you tes!ng across domain boundaries?
Image credits
• Human Evolu+on by Tkgd2007
h-p://bit.ly/1DdLvy1 (CC BY-SA 3.0)
• Oops by Steve and Sara Emry
h-ps://flic.kr/p/9Z1EEd (CC BY-NC-SA 2.0)
• Blueprints for Willborough Home by Brian Tobin
h-ps://flic.kr/p/7MP9RU (CC BY-NC-ND 2.0)
• Border by Giulia van Pelt
h-ps://flic.kr/p/9YT1c5 (CC BY-NC-ND 2.0)
Thank you!
h"ps://joind.in/16248
@ciaranmcnulty

More Related Content

What's hot

Test in action week 3
Test in action   week 3Test in action   week 3
Test in action week 3Yi-Huan Chan
 
TDD Training
TDD TrainingTDD Training
TDD Training
Manuela Grindei
 
Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013
Dror Helper
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2Yi-Huan Chan
 
Clean code & design patterns
Clean code & design patternsClean code & design patterns
Clean code & design patterns
Pascal Larocque
 
.NET Coding Standards For The Real World (2012)
.NET Coding Standards For The Real World (2012).NET Coding Standards For The Real World (2012)
.NET Coding Standards For The Real World (2012)
David McCarter
 
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
GeeksLab Odessa
 
Google mock for dummies
Google mock for dummiesGoogle mock for dummies
Google mock for dummies
Harry Potter
 
Testing the Untestable
Testing the UntestableTesting the Untestable
Testing the Untestable
Mark Baker
 
PHP 7 Crash Course
PHP 7 Crash CoursePHP 7 Crash Course
PHP 7 Crash Course
Colin O'Dell
 
PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better Code
SWIFTotter Solutions
 
ReactJS for Programmers
ReactJS for ProgrammersReactJS for Programmers
ReactJS for Programmers
David Rodenas
 
Interaction testing using mock objects
Interaction testing using mock objectsInteraction testing using mock objects
Interaction testing using mock objectsLim Chanmann
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practices
Ankit Rastogi
 
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
GeeksLab Odessa
 
Developer testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing FanaticDeveloper testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing Fanatic
LB Denker
 
Creating Gradle Plugins - GR8Conf US
Creating Gradle Plugins - GR8Conf USCreating Gradle Plugins - GR8Conf US
Creating Gradle Plugins - GR8Conf US
Annyce Davis
 

What's hot (19)

Test in action week 3
Test in action   week 3Test in action   week 3
Test in action week 3
 
TDD Training
TDD TrainingTDD Training
TDD Training
 
Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2
 
Clean code & design patterns
Clean code & design patternsClean code & design patterns
Clean code & design patterns
 
.NET Coding Standards For The Real World (2012)
.NET Coding Standards For The Real World (2012).NET Coding Standards For The Real World (2012)
.NET Coding Standards For The Real World (2012)
 
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
 
Google mock for dummies
Google mock for dummiesGoogle mock for dummies
Google mock for dummies
 
Testing the Untestable
Testing the UntestableTesting the Untestable
Testing the Untestable
 
TDD, BDD and mocks
TDD, BDD and mocksTDD, BDD and mocks
TDD, BDD and mocks
 
PHP 7 Crash Course
PHP 7 Crash CoursePHP 7 Crash Course
PHP 7 Crash Course
 
PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better Code
 
ReactJS for Programmers
ReactJS for ProgrammersReactJS for Programmers
ReactJS for Programmers
 
Laravel Unit Testing
Laravel Unit TestingLaravel Unit Testing
Laravel Unit Testing
 
Interaction testing using mock objects
Interaction testing using mock objectsInteraction testing using mock objects
Interaction testing using mock objects
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practices
 
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
 
Developer testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing FanaticDeveloper testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing Fanatic
 
Creating Gradle Plugins - GR8Conf US
Creating Gradle Plugins - GR8Conf USCreating Gradle Plugins - GR8Conf US
Creating Gradle Plugins - GR8Conf US
 

Viewers also liked

Iahr Ruskauff
Iahr RuskauffIahr Ruskauff
Iahr Ruskauff
Greg Ruskauff
 
HE Profiles Oct 2012
HE Profiles Oct 2012HE Profiles Oct 2012
HE Profiles Oct 2012bwcelearning
 
Education in india
Education in indiaEducation in india
Education in india
Peda Babu Vadiyala
 
Ինչպե՞ս գրել ինտերնետի համար
Ինչպե՞ս գրել ինտերնետի համարԻնչպե՞ս գրել ինտերնետի համար
Ինչպե՞ս գրել ինտերնետի համար
Artur Papyan
 
MBA Certificate with Transcripts
MBA Certificate with TranscriptsMBA Certificate with Transcripts
MBA Certificate with TranscriptsRoman Solovyov
 
In Pursuit of Tea
In Pursuit of TeaIn Pursuit of Tea
In Pursuit of Tea
Matt Redington
 
El agua y los electrolitos
El agua y los electrolitosEl agua y los electrolitos
El agua y los electrolitos
mark11
 
04 shock
04 shock04 shock
MBA Certificate -Authenticated
MBA Certificate -AuthenticatedMBA Certificate -Authenticated
MBA Certificate -AuthenticatedAjay Abraham
 
Antonio d'alì - programma Sponde
Antonio d'alì - programma SpondeAntonio d'alì - programma Sponde
Antonio d'alì - programma Sponde
Antonio d'Alì
 
M.E PROVISIONAL CERTIFICATE
M.E PROVISIONAL CERTIFICATEM.E PROVISIONAL CERTIFICATE
M.E PROVISIONAL CERTIFICATEMuhammad Hasan
 
Out of the box replication in postgres 9.4(pg confus)
Out of the box replication in postgres 9.4(pg confus)Out of the box replication in postgres 9.4(pg confus)
Out of the box replication in postgres 9.4(pg confus)
Denish Patel
 
10 conceptos básicos del balance hidroelectrolítico
10 conceptos básicos del balance hidroelectrolítico10 conceptos básicos del balance hidroelectrolítico
10 conceptos básicos del balance hidroelectrolíticoice
 
Decouple your framework now, thank me later
Decouple your framework now, thank me laterDecouple your framework now, thank me later
Decouple your framework now, thank me later
Michelangelo van Dam
 
Drenaje de las calles campo
Drenaje de las calles campoDrenaje de las calles campo
Drenaje de las calles campo
Jaime amambal
 
5min analyse
5min analyse5min analyse
5min analyse
Hans-Jürgen Schönig
 

Viewers also liked (18)

Iahr Ruskauff
Iahr RuskauffIahr Ruskauff
Iahr Ruskauff
 
HE Profiles Oct 2012
HE Profiles Oct 2012HE Profiles Oct 2012
HE Profiles Oct 2012
 
Education in india
Education in indiaEducation in india
Education in india
 
Ինչպե՞ս գրել ինտերնետի համար
Ինչպե՞ս գրել ինտերնետի համարԻնչպե՞ս գրել ինտերնետի համար
Ինչպե՞ս գրել ինտերնետի համար
 
MBA Certificate with Transcripts
MBA Certificate with TranscriptsMBA Certificate with Transcripts
MBA Certificate with Transcripts
 
Goldhill_Jason Scott
Goldhill_Jason ScottGoldhill_Jason Scott
Goldhill_Jason Scott
 
In Pursuit of Tea
In Pursuit of TeaIn Pursuit of Tea
In Pursuit of Tea
 
El agua y los electrolitos
El agua y los electrolitosEl agua y los electrolitos
El agua y los electrolitos
 
bulats
bulatsbulats
bulats
 
04 shock
04 shock04 shock
04 shock
 
MBA Certificate -Authenticated
MBA Certificate -AuthenticatedMBA Certificate -Authenticated
MBA Certificate -Authenticated
 
Antonio d'alì - programma Sponde
Antonio d'alì - programma SpondeAntonio d'alì - programma Sponde
Antonio d'alì - programma Sponde
 
M.E PROVISIONAL CERTIFICATE
M.E PROVISIONAL CERTIFICATEM.E PROVISIONAL CERTIFICATE
M.E PROVISIONAL CERTIFICATE
 
Out of the box replication in postgres 9.4(pg confus)
Out of the box replication in postgres 9.4(pg confus)Out of the box replication in postgres 9.4(pg confus)
Out of the box replication in postgres 9.4(pg confus)
 
10 conceptos básicos del balance hidroelectrolítico
10 conceptos básicos del balance hidroelectrolítico10 conceptos básicos del balance hidroelectrolítico
10 conceptos básicos del balance hidroelectrolítico
 
Decouple your framework now, thank me later
Decouple your framework now, thank me laterDecouple your framework now, thank me later
Decouple your framework now, thank me later
 
Drenaje de las calles campo
Drenaje de las calles campoDrenaje de las calles campo
Drenaje de las calles campo
 
5min analyse
5min analyse5min analyse
5min analyse
 

Similar to Why Your Test Suite Sucks - PHPCon PL 2015

Building Better Applications with Data::Manager
Building Better Applications with Data::ManagerBuilding Better Applications with Data::Manager
Building Better Applications with Data::ManagerJay Shirley
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
Michelangelo van Dam
 
Php tests tips
Php tests tipsPhp tests tips
Php tests tips
Damian Sromek
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
Konstantin Kudryashov
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
Michelangelo van Dam
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Michelangelo van Dam
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitmfrost503
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnit
mfrost503
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
Michelangelo van Dam
 
Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023
Mark Niebergall
 
Test driven development
Test driven developmentTest driven development
Test driven development
christoforosnalmpantis
 
Test driven development_for_php
Test driven development_for_phpTest driven development_for_php
Test driven development_for_php
Lean Teams Consultancy
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
Michelangelo van Dam
 
Test doubles
Test doublesTest doubles
OOP Is More Than Cars and Dogs
OOP Is More Than Cars and DogsOOP Is More Than Cars and Dogs
OOP Is More Than Cars and Dogs
Chris Tankersley
 
What's new in Doctrine
What's new in DoctrineWhat's new in Doctrine
What's new in Doctrine
Jonathan Wage
 
Effective PHP. Part 3
Effective PHP. Part 3Effective PHP. Part 3
Effective PHP. Part 3
Vasily Kartashov
 
Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013
Michelangelo van Dam
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfast
Michelangelo van Dam
 

Similar to Why Your Test Suite Sucks - PHPCon PL 2015 (20)

Building Better Applications with Data::Manager
Building Better Applications with Data::ManagerBuilding Better Applications with Data::Manager
Building Better Applications with Data::Manager
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Php tests tips
Php tests tipsPhp tests tips
Php tests tips
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnit
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnit
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023
 
Test driven development
Test driven developmentTest driven development
Test driven development
 
Test driven development_for_php
Test driven development_for_phpTest driven development_for_php
Test driven development_for_php
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Test doubles
Test doublesTest doubles
Test doubles
 
OOP Is More Than Cars and Dogs
OOP Is More Than Cars and DogsOOP Is More Than Cars and Dogs
OOP Is More Than Cars and Dogs
 
What's new in Doctrine
What's new in DoctrineWhat's new in Doctrine
What's new in Doctrine
 
Magento code audit
Magento code auditMagento code audit
Magento code audit
 
Effective PHP. Part 3
Effective PHP. Part 3Effective PHP. Part 3
Effective PHP. Part 3
 
Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfast
 

More from CiaranMcNulty

Greener web development at PHP London
Greener web development at PHP LondonGreener web development at PHP London
Greener web development at PHP London
CiaranMcNulty
 
Doodle Driven Development
Doodle Driven DevelopmentDoodle Driven Development
Doodle Driven Development
CiaranMcNulty
 
Behat Best Practices with Symfony
Behat Best Practices with SymfonyBehat Best Practices with Symfony
Behat Best Practices with Symfony
CiaranMcNulty
 
Behat Best Practices
Behat Best PracticesBehat Best Practices
Behat Best Practices
CiaranMcNulty
 
Behat Best Practices with Symfony
Behat Best Practices with SymfonyBehat Best Practices with Symfony
Behat Best Practices with Symfony
CiaranMcNulty
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through Examples
CiaranMcNulty
 
Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016
CiaranMcNulty
 
Conscious Coupling
Conscious CouplingConscious Coupling
Conscious Coupling
CiaranMcNulty
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through Examples
CiaranMcNulty
 
Conscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHPConscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHP
CiaranMcNulty
 
TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016
CiaranMcNulty
 
Fly In Style (without splashing out)
Fly In Style (without splashing out)Fly In Style (without splashing out)
Fly In Style (without splashing out)
CiaranMcNulty
 
Driving Design through Examples - PhpCon PL 2015
Driving Design through Examples - PhpCon PL 2015Driving Design through Examples - PhpCon PL 2015
Driving Design through Examples - PhpCon PL 2015
CiaranMcNulty
 
Building a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing StrategiesBuilding a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing Strategies
CiaranMcNulty
 
TDD with PhpSpec
TDD with PhpSpecTDD with PhpSpec
TDD with PhpSpec
CiaranMcNulty
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through Examples
CiaranMcNulty
 
Why Your Test Suite Sucks
Why Your Test Suite SucksWhy Your Test Suite Sucks
Why Your Test Suite Sucks
CiaranMcNulty
 
Driving Design with PhpSpec
Driving Design with PhpSpecDriving Design with PhpSpec
Driving Design with PhpSpec
CiaranMcNulty
 
Using HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless IntegrationUsing HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless Integration
CiaranMcNulty
 

More from CiaranMcNulty (19)

Greener web development at PHP London
Greener web development at PHP LondonGreener web development at PHP London
Greener web development at PHP London
 
Doodle Driven Development
Doodle Driven DevelopmentDoodle Driven Development
Doodle Driven Development
 
Behat Best Practices with Symfony
Behat Best Practices with SymfonyBehat Best Practices with Symfony
Behat Best Practices with Symfony
 
Behat Best Practices
Behat Best PracticesBehat Best Practices
Behat Best Practices
 
Behat Best Practices with Symfony
Behat Best Practices with SymfonyBehat Best Practices with Symfony
Behat Best Practices with Symfony
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through Examples
 
Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016
 
Conscious Coupling
Conscious CouplingConscious Coupling
Conscious Coupling
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through Examples
 
Conscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHPConscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHP
 
TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016
 
Fly In Style (without splashing out)
Fly In Style (without splashing out)Fly In Style (without splashing out)
Fly In Style (without splashing out)
 
Driving Design through Examples - PhpCon PL 2015
Driving Design through Examples - PhpCon PL 2015Driving Design through Examples - PhpCon PL 2015
Driving Design through Examples - PhpCon PL 2015
 
Building a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing StrategiesBuilding a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing Strategies
 
TDD with PhpSpec
TDD with PhpSpecTDD with PhpSpec
TDD with PhpSpec
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through Examples
 
Why Your Test Suite Sucks
Why Your Test Suite SucksWhy Your Test Suite Sucks
Why Your Test Suite Sucks
 
Driving Design with PhpSpec
Driving Design with PhpSpecDriving Design with PhpSpec
Driving Design with PhpSpec
 
Using HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless IntegrationUsing HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless Integration
 

Recently uploaded

Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
XfilesPro
 
Enterprise Resource Planning System in Telangana
Enterprise Resource Planning System in TelanganaEnterprise Resource Planning System in Telangana
Enterprise Resource Planning System in Telangana
NYGGS Automation Suite
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Globus
 
Pro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp BookPro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp Book
abdulrafaychaudhry
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
Neo4j
 
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdfDominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
AMB-Review
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
Juraj Vysvader
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
Donna Lenk
 
APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)
Boni García
 
Top 7 Unique WhatsApp API Benefits | Saudi Arabia
Top 7 Unique WhatsApp API Benefits | Saudi ArabiaTop 7 Unique WhatsApp API Benefits | Saudi Arabia
Top 7 Unique WhatsApp API Benefits | Saudi Arabia
Yara Milbes
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
Matt Welsh
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
Globus
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
Aftab Hussain
 
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI AppAI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
Google
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
Paco van Beckhoven
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
rickgrimesss22
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
Ortus Solutions, Corp
 
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata
 

Recently uploaded (20)

Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
 
Enterprise Resource Planning System in Telangana
Enterprise Resource Planning System in TelanganaEnterprise Resource Planning System in Telangana
Enterprise Resource Planning System in Telangana
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
 
Pro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp BookPro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp Book
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
 
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdfDominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
 
APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)APIs for Browser Automation (MoT Meetup 2024)
APIs for Browser Automation (MoT Meetup 2024)
 
Top 7 Unique WhatsApp API Benefits | Saudi Arabia
Top 7 Unique WhatsApp API Benefits | Saudi ArabiaTop 7 Unique WhatsApp API Benefits | Saudi Arabia
Top 7 Unique WhatsApp API Benefits | Saudi Arabia
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
 
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI AppAI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
 
BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024BoxLang: Review our Visionary Licenses of 2024
BoxLang: Review our Visionary Licenses of 2024
 
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
 

Why Your Test Suite Sucks - PHPCon PL 2015

  • 1. Why Your Test Suite Sucks (and what you can do about it) by Ciaran McNulty at PHPCon Poland 2015
  • 2. It’s not working for me === TDD must suck1 1 BIT.LY/1LEF0GI & BIT.LY/1SLFGTQ
  • 3. The problem is not TDD
  • 4. The problem is your suite
  • 6. Suites suck when you aren’t ge)ng all the benefits of TDD
  • 7. Suites suck when the tests are hard to maintain
  • 8. Reason 1: You don't have a test suite
  • 9. The Evolu*on of a TDD Team
  • 10. Maturity model • Manual tes&ng • Automated tes&ng • Test-first development • Test-driven development
  • 11. Manual tes*ng • Design an implementa+on • Implement that design • Manually test
  • 12. Growing from Manual to Automated • “When we make changes, it breaks things!” • “We spend a lot of /me on manual tes:ng” • “Bugs keep making it into produc:on” Enabled by: - Tutorials, training - Team policies
  • 13. Automated tes+ng • Design an implementa+on • Implement that design • Write tests to verify it
  • 14. Growing from Automated to Test-first • “It’s a pain having to write tests once I’m done” • “My test suite is bri'le” • “Maintaining the suite is hard” • ”TDD Doesn’t Work!” Supported by: - Coaching, pairing - Leadership
  • 15. Test-first development • Design an implementa+on • Write tests to verify that implementa+on • Implement that design
  • 16. Growing from Test-first to Test-driven • “Test suite is s"ll bri,le” • “Maintaining the suite is s"ll hard” • ”TDD Doesn’t Work!” Supported by: - Prac1ce
  • 17. Test-driven development • Write tests that describe behaviour • Implement a system that has that behaviour Problems: - “I don’t know what to do with all this spare 'me!” - “Where should we keep this extra money?”
  • 18. Reason 2: You are tes*ng implementa*on
  • 19. Problem: Mocking Queries • A query is a method that returns a value without side effects • We shouldn’t care how many 4mes (if any) a query is called • Specifying that detail makes change harder
  • 20. function testItGreetsPeopleByName() { $user = $this->getMock('User'); $user->expects($this->once()) ->method('getName') ->willReturn('Ciaran'); $greeting = $this->greeter->greet($user); $this->assertEquals('Hello, Ciaran!', $greeting); }
  • 21. function testItGreetsPeopleByName() { $user = $this->getMock('User'); $user->method('getName') ->willReturn('Ciaran'); $greeting = $this->greeter->greet($user); $this->assertEquals('Hello, Ciaran!', $greeting); }
  • 22. Don’t mock queries, just use stubs Do you really care how many /mes it's called?
  • 23. Problem: Tes,ng the sequence of calls • Most of the *me we don’t care what order calls are made in • Tes*ng the sequence makes it hard to change
  • 24. public function testBasketTotals() { $priceList = $this->getMock('PriceList'); $priceList->expect($this->at(0)) ->method('getPrices') ->willReturn(120); $priceList->expect($this->at(1)) ->method('getPrices') ->willReturn(200); $this->basket->add('Milk', 'Bread'); $total = $this->basket->calculateTotal(); $this->assertEqual(320, $total); }
  • 25. public function testBasketTotals() { $priceList = $this->getMock('PriceList'); $priceList->method('getPrices') ->will($this->returnValueMap([ ['Milk', 120], ['Bread', 200] ])); $this->basket->add('Milk', 'Bread'); $total = $this->basket->calculateTotal(); $this->assertEqual(320, $total); }
  • 26. Test behaviour you care about, don’t test implementa/on PROTIP: The best way to do this is to not have an implementa3on yet
  • 27. Reason 3: Because your design sucks
  • 28. Problem: Too many Doubles • It is painful to have to double lots of objects in your test • It is a signal your object has too many dependencies
  • 29. public function setUp() { $chargerules = $this->getMock('ChargeRules'); $chargetypes = $this->getMock('ChargeTypes'); $notifier = $this->getMockBuilder('Notifier') ->disableOriginalConstructor()->getMock(); $this->processor = new InvoiceProcessor( $chargerules, $chargetypes, $notifier ); }
  • 30. class InvoiceProcessor { public function __construct( ChargeRules $chargeRules, ChargeTypes $chargeTypes, Notifier $notifier ) { $this->chargeRules = $chargeRules; $this->chargeTypes = $chargeTypes; $this->notifier = $notifier; } // …
  • 31. Too many doubles in your test mean your class has too many dependencies
  • 32. Problem: Stubs returning stubs • A related painful issue is stubs returning a stubs • It is a signal our object does not have the right dependencies
  • 33. public function testItNotifiesTheUser() { $user = $this->getMock(User::class); $contact = $this->getMock(Contact::class); $email = $this->getMock(Email::class); $emailer = $this->getMock(Emailer::class); $user->method('getContact')->willReturn($contact); $contact->method('getEmail')->willReturn($email); $emailer->expects($this->once) ->method('sendTo') ->with($this->equalTo($email)); (new Notifier($emailer))->notify($user); }
  • 34. class Notifier { public function __construct(Emailer $emailer) { // … } public function notify(User $user) { $email = $user->getContact()->getEmail() $this->emailer->sendTo($email); } }
  • 35. class Notifier { public function __construct(Emailer $emailer) { // … } public function notify(User $user) { $this->emailer->sendTo($user); } }
  • 36. class Notifier { public function __construct(Emailer $emailer) { // … } public function notify(Email $email) { $this->emailer->sendTo($email); } }
  • 37. public function testItNotifiesTheUser() { $email = $this->getMock(Email::class); $emailer = $this->getMock(Emailer::class); $emailer->expects($this->once) ->method('sendTo') ->with($this->equalTo($email)); (new Notifier($emailer))->notify($user); }
  • 38. Stubs returning stubs indicate dependencies are not correctly defined
  • 39. Problem: Par+ally doubling the object under test • A common ques*on is “how can I mock methods on the SUT?” • Easy to do in some tools, impossible in others • It is a signal our object has too many responsibili*es
  • 40. class Form { public function handle($data) { if ($this->validate($data)) { return 'Valid'; } return 'Invalid'; } protected function validate($data) { // do something complex } }
  • 41. function testItOutputsMessageOnValidData() { $form = $this->getMock('Form', ['validate']); $form->method('validate')->willReturn(true); $result = $form->handle([]); $this->assertSame('Valid', $result); }
  • 42. class Form { protected function __construct(Validator $validator) { // … } public function handle($data) { if ($this->validator->validate($data)) { return 'Valid'; } return 'Invalid'; } }
  • 43. function testItOutputsMessageOnValidData() { $validator = $this->getMock(‘Validator’); $validator->method('validate')->willReturn(true); $form = new Form($validator); $result = $form->handle([]); $this->assertSame('Valid', $result); }
  • 44. If you want to mock part of the SUT it means you should really have more than one object
  • 45. How to be a be)er so,ware designer: • Stage 1: Think about your code before you write it • Stage 2: Write down those thoughts • Stage 3: Write down those thoughts as code
  • 46. How long will it take without TDD? • 1 hour thinking about how it should work • 30 mins Implemen6ng it • 30 mins Checking it works
  • 47. How long will it take with TDD? • 1 hour Thinking in code about how it should work • 30 mins Implemen8ng it • 1 min Checking it works
  • 48. Use your test suite as a way to reason about the code
  • 49. Customers should not dictate your design process
  • 50. Reason 4: You are unit tes,ng across domain boundaries
  • 51. Problem: Tes,ng 3rd party code • When we extend a library or framework we use other people’s code • To test our code we end up tes.ng their code too • This :me is wasted – we should trust their code works
  • 52. class UserRepository extends FrameworkRepository { public function findByEmail($email) { $this->find(['email' => $email]); } }
  • 53. public function testItFindsTheUserByEmail() { $db = $this->getMock(FrameworkDatabaseConnection::class); $schemaCreator = $this->getMock(FrameworkSchemaCreator::class); $schema = $this->getMock(FrameworkSchema::class); $schemaCreator->method('getSchema')->willReturn($schema); $schema->method('getMappings')->willReturn(['email'=>'email']); $db->method('query')->willReturn(['email'=>'bob@example.com'); $repo = new UserRepository($db, $schemaCreator); $user = $repo->findByEmail('bob@example.com'); $this->assertType(User::class, $user); }
  • 54. class UserRepository { private $repository; public function __construct(FrameworkRepository $repository) { $this->repository = $repository; } public function findByEmail($email) { return $this->repository->find(['email' => $email]); } }
  • 55. public function testItFindsTheUserByEmail() { $fwRepo = $this->getMock(FrameworkRepository::class); $user = $this->getMock(User::class); $repository = new UserRepository($fwRepo); $fwRepo->method('find') ->with(['email' => 'bob@example.com') ->willReturn($user); $actualUser = $repository->findByEmail('bob@example.com'); $this->assertEqual($user, $actualUser); }
  • 56. When you extend third party code, you take responsibility for its design decisions
  • 58. Problem: Doubling 3rd party code • Test Doubles (Mocks, Stubs, Fakes) are used to test communica(on between objects • Tes:ng against a Double of a 3rd party object does not give us confidence that we have described the communica:on correctly
  • 59. public function testItUploadsValidDataToTheCloud() { $validator = $this->getMock(FileValidator::class); $client = $this->getMock(CloudApi::class); $file = $this->getMock(File::class); $validator->method('validate') ->with($this->equalTo($file)) ->willReturn(true); $validator->expects($this->once())->method('startUpload'); $client->expects($this->once())->method('uploadData'); $client->expects($this->once()) ->method('uploadSuccessful') ->willReturn(true); (new FileHandler($client, $validator))->process($file); }
  • 64. public function testItUploadsValidDataToTheCloud() { $fileStore = $this->getMock(FileStore::class); $file = $this->getMock(File::class); $validator->method('validate') ->with($this->equalTo($file)) ->willReturn(true); (new FileHandler($fileStore, $validator))->process($file); }
  • 66. class CloudFilestoreTest extends PHPUnit_Framework_TestCase { /** @group integration */ function testItStoresFiles() { $testCredentials = … $file = new File(…); $apiClient = new CloudApi($testCredentials); $filestore = new CloudFileStore($apiClient); $filestore->store($file); $this->assertTrue($apiClient->fileExists(…)); } }
  • 68. Don’t test other people’s code You don't know how it's supposed to behave
  • 69. Don’t test how you talk to other people’s code You don't know how it's supposed to respond
  • 70. Pu#ng it all together • Use TDD to drive development • Use TDD to replace exis1ng prac1ces, not as a new extra task
  • 71. Pu#ng it all together Don’t ignore tests that suck, improve them: • Is the test too !ed to implementa!on? • Does the design of the code need to improve? • Are you tes!ng across domain boundaries?
  • 72. Image credits • Human Evolu+on by Tkgd2007 h-p://bit.ly/1DdLvy1 (CC BY-SA 3.0) • Oops by Steve and Sara Emry h-ps://flic.kr/p/9Z1EEd (CC BY-NC-SA 2.0) • Blueprints for Willborough Home by Brian Tobin h-ps://flic.kr/p/7MP9RU (CC BY-NC-ND 2.0) • Border by Giulia van Pelt h-ps://flic.kr/p/9YT1c5 (CC BY-NC-ND 2.0)