SlideShare una empresa de Scribd logo
1 de 73
Descargar para leer sin conexión
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

Más contenido relacionado

La actualidad más candente

Test in action week 3
Test in action   week 3Test in action   week 3
Test in action week 3Yi-Huan Chan
 
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 2013Dror 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 patternsPascal 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 dummiesHarry Potter
 
Testing the Untestable
Testing the UntestableTesting the Untestable
Testing the UntestableMark Baker
 
PHP 7 Crash Course
PHP 7 Crash CoursePHP 7 Crash Course
PHP 7 Crash CourseColin 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 CodeSWIFTotter Solutions
 
ReactJS for Programmers
ReactJS for ProgrammersReactJS for Programmers
ReactJS for ProgrammersDavid 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 practicesAnkit 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 FanaticLB Denker
 
Creating Gradle Plugins - GR8Conf US
Creating Gradle Plugins - GR8Conf USCreating Gradle Plugins - GR8Conf US
Creating Gradle Plugins - GR8Conf USAnnyce Davis
 

La actualidad más candente (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
 

Destacado

HE Profiles Oct 2012
HE Profiles Oct 2012HE Profiles Oct 2012
HE Profiles Oct 2012bwcelearning
 
Ինչպե՞ս գրել ինտերնետի համար
Ինչպե՞ս գրել ինտերնետի համարԻնչպե՞ս գրել ինտերնետի համար
Ինչպե՞ս գրել ինտերնետի համարArtur Papyan
 
MBA Certificate with Transcripts
MBA Certificate with TranscriptsMBA Certificate with Transcripts
MBA Certificate with TranscriptsRoman Solovyov
 
El agua y los electrolitos
El agua y los electrolitosEl agua y los electrolitos
El agua y los electrolitosmark11
 
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 SpondeAntonio 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 laterMichelangelo van Dam
 
Drenaje de las calles campo
Drenaje de las calles campoDrenaje de las calles campo
Drenaje de las calles campoJaime amambal
 

Destacado (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 a 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
 
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 mockingKonstantin 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 tek12Michelangelo 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 PHPUnitmfrost503
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11Michelangelo 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] 2023Mark Niebergall
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxMichelangelo van Dam
 
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 DogsChris Tankersley
 
What's new in Doctrine
What's new in DoctrineWhat's new in Doctrine
What's new in DoctrineJonathan Wage
 
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 2013Michelangelo 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 - phpbelfastMichelangelo van Dam
 

Similar a 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
 

Más de CiaranMcNulty

Greener web development at PHP London
Greener web development at PHP LondonGreener web development at PHP London
Greener web development at PHP LondonCiaranMcNulty
 
Doodle Driven Development
Doodle Driven DevelopmentDoodle Driven Development
Doodle Driven DevelopmentCiaranMcNulty
 
Behat Best Practices with Symfony
Behat Best Practices with SymfonyBehat Best Practices with Symfony
Behat Best Practices with SymfonyCiaranMcNulty
 
Behat Best Practices
Behat Best PracticesBehat Best Practices
Behat Best PracticesCiaranMcNulty
 
Behat Best Practices with Symfony
Behat Best Practices with SymfonyBehat Best Practices with Symfony
Behat Best Practices with SymfonyCiaranMcNulty
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through ExamplesCiaranMcNulty
 
Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016CiaranMcNulty
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through ExamplesCiaranMcNulty
 
Conscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHPConscious Decoupling - Lone Star PHP
Conscious Decoupling - Lone Star PHPCiaranMcNulty
 
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 2016CiaranMcNulty
 
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 2015CiaranMcNulty
 
Building a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing StrategiesBuilding a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing StrategiesCiaranMcNulty
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through ExamplesCiaranMcNulty
 
Why Your Test Suite Sucks
Why Your Test Suite SucksWhy Your Test Suite Sucks
Why Your Test Suite SucksCiaranMcNulty
 
Driving Design with PhpSpec
Driving Design with PhpSpecDriving Design with PhpSpec
Driving Design with PhpSpecCiaranMcNulty
 
Using HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless IntegrationUsing HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless IntegrationCiaranMcNulty
 

Más de 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
 

Último

chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Intelisync
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 

Último (20)

chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 

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)