Getting Started With TDD
Eric Hogue - @ehogue
Confoo - 2014-02-27
TDD
Where should I
Start?
1. Unit tests
2. Test Driven Development
3. What’s next?
Unit Tests
Unit Test
a method by which individual units of source
code [...] are tested to determine if they are fit
for use
http://e...
Don’t Cross boundaries
Tools
●
●
●
●

SimpleTest
atoum
PHPT
PHPUnit
Installation - Phar
$ wget
https://phar.phpunit.de/phpunit.phar
$ chmod +x phpunit.phar
$ mv phpunit.phar /usr/local/bin/p...
Installation - Pear
pear config-set auto_discover 1
pear install pear.phpunit.de/PHPUnit
Installation - Composer
# composer.json
{
"require-dev": {
"phpunit/phpunit": "3.7.*"
}
}
$ composer install
PHPUnit
FactorialTest.php
<?php
class FactorialTest extends
PHPUnit_Framework_TestCase {
}
public function testSomething() {
}
/** @test */
public function somethingElse() {
}
● Arrange
● Act
● Assert
Arrange
/** @test */
public function factOf1() {
$factorial = new Factorial;
}
Act
/** @test */
public function factOf1() {
$factorial = new Factorial;
$result = $factorial->fact(1);
}
Assert
/** @test */
public function factOf1() {
$factorial = new Factorial;
$result = $factorial->fact(1);
$this->assertSa...
PHPUnit Assertions
●
●
●
●
●
●
●

$this->assertTrue();
$this->assertEquals();
$this->assertSame();
$this->assertContains()...
Preparing For Your Tests
setup() -> Before every tests
teardown() -> After every tests
setUpBeforeClass() + tearDownAfterC...
phpunit.xml
<phpunit bootstrap="bootstrap.php"
colors="true"
strict="true"
verbose="true"
>
...
</phpunit>
phpunit.xml
<phpunit>
<testsuites>
<testsuite name="My Test Suite">
<directory>path</directory>
<file>path</file>
<exclude...
TDD
Red - Green - Refactor
Red
Write a failing test
Red - Green - Refactor
Green
Make it pass
Red - Green - Refactor
Refactor
Fix any shortcuts you took
/** @test */
public function create() {
$this->assertNotNull(new Factorial);
}
class Factorial {
}
/** @test */
public function factOf1() {
$facto = new Factorial;
$this->assertSame(1,
$facto->fact(1));
}
public function fact($number) {
return 1;
}
Duplication
public function create() {
$this->assertNotNull(new Factorial);
}
public function factOf1() {
$facto = new Fac...
public function setup() {
$this->facto = new Factorial;
}
/** @test */
public function factOf1() {
$this->assertSame(1,
$t...
/** @test */
public function factOf2() {
$this->assertSame(2,
$this->facto->fact(2));
}
public function fact($number) {
return $number;
}
More duplication
/** @test */
public function factOf1() {
$this->assertSame(1,
$this->facto->fact(1));
}
/** @test */
publ...
public function factDataProvider() {
return array(
array(1, 1),
array(2, 2),
);
}
/**
* @test
* @dataProvider factDataProvider
*/
public function factorial($number,
$expected) {
...
…
$result =
$this->facto->fact($number);
$this->assertSame($expected,
$result);
}
public function factDataProvider() {
…
array(2, 2),
array(3, 6),
...
public function fact($number) {
if ($number < 2) return 1;
return $number *
$this->fact($number - 1);
}
It’s a lot of
work
Dependencies
Problems
class Foo {
public function __construct() {
$this->bar = new Bar;
}
}
Dependency Injection
Setter Injection
class Foo {
public function setBar(Bar $bar) {
$this->bar = $bar;
}
public function doSomething() {
// Us...
Constructor Injection
class Foo {
public function __construct(
Bar $bar) {
$this->bar = $bar;
}
public function doSomethin...
Pass the dependency directly
class Foo {
public function doSomething(
Bar $bar) {
// Use $bar
}
}
File System
vfsStream
Virtual Files System
composer.json
"require-dev": {
"mikey179/vfsStream": "*"
},
Check if a folder was created
$root = vfsStream::setup('dir');
$parentDir = $root->url('dir');
//Code creating sub folder
...
Reading a file
$struct = array(
'subDir' => array('test.txt'
=> 'content')
);
$root = vfsStream::setup('root',
null, $stru...
Reading a file
…
$content = file_get_contents(
$parentDir . '/subDir/test.txt');
$this->assertSame('content',
$content);
Databases
Mocks
Replaces a dependency
● PHPUnit mocks
● Mockery
● Phake
Creation
$mock = $this->getMock('NSClass');
Creation
$mock = $this->getMock('NSClass');
Or
$mock = $this->getMockBuilder
('NamespaceClass')
->disableOriginalConstruct...
$mock->expects($this->once())
->method('methodName')
$mock->expects($this->once())
->method('methodName')
->with(1, 'aa', $this->anything())
$mock->expects($this->once())
->method('methodName')
->with(1, 'aa', $this->anything())
->will($this->returnValue(10));
Mocking PDO
$statement = $this->getMockBuilder
('PDOStatement')
->getMock();
$statement->expects($this->once())
->method('...
...
$statement->expects($this->once())
->method('fetchAll')
->will(
$this->returnValue(
array(array('id' => 123))
)
);
...
$this->getMockBuilder('PDO')
->getMock();
…
$pdo = $this->getMockBuilder(
'stdClass')
->setMethods(array('prepare'))
->getMock();
$pdo->expects($this->once())
->met...
class PDOMock extends PDO {
public function __construct() {}
}
$pdo = $this->getMockBuilder
('PDOMock')
->getMock();
mysql_*
DbUnit Extension
extends
PHPUnit_Extensions_Database_TestCase
public function getConnection() {
$pdo = new PDO('sqlite::me...
public function getDataSet() {
return $this->
createFlatXMLDataSet('file');
}
API
● Wrap all call into a class
○ ZendHttp
○ Guzzle
○ Simple class that uses curl

● Mock the class
○ Return the wanted xml/j...
Pros and Cons
Pros
● Less regressions
Pros
● Less regressions
● Trust
Pros
● Less regressions
● Trust
● Low coupling
Pros
●
●
●
●

Less regressions
Trust
Low coupling
Simple Design
Cons
● Takes longer
“If it doesn't have to
work, I can get it done a
lot faster!”
- Kent Beck
Cons
● Takes longer
● Can be hard to sell to managers
Cons
● Takes longer
● Can be hard to sell to managers
● It’s hard
Prochaines étapes?
Continuous Testing - Guard
Continuous Integration
Continuous Integration
● Run your tests automatically
○
○
○
○

Unit Tests
Acceptance Tests
Performance Tests
...
Continuous Integration
● Run your tests automatically
○
○
○
○

Unit Tests
Acceptance Tests
Performance Tests
…

● Check St...
Continuous Integration
● Run your tests automatically
○
○
○
○

Unit Tests
Acceptance Tests
Performance Tests
…

● Check St...
Questions
Twitter:
@ehogue
Blog:
http://erichogue.ca/
Slides: http://www.
slideshare.net/EricHogue
Credits
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●

Paul - http://www.flickr.com/photos/pauldc/4626637600/in/photostream/
JaseMan - htt...
Getting started with TDD - Confoo 2014
Getting started with TDD - Confoo 2014
Getting started with TDD - Confoo 2014
Upcoming SlideShare
Loading in...5
×

Getting started with TDD - Confoo 2014

1,106

Published on

Introduction to Test Driven Development. I gave that talk on February 2014 at Confoo.

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,106
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
9
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Getting started with TDD - Confoo 2014

  1. 1. Getting Started With TDD Eric Hogue - @ehogue Confoo - 2014-02-27
  2. 2. TDD
  3. 3. Where should I Start?
  4. 4. 1. Unit tests 2. Test Driven Development 3. What’s next?
  5. 5. Unit Tests
  6. 6. Unit Test a method by which individual units of source code [...] are tested to determine if they are fit for use http://en.wikipedia.org/wiki/Unit_testing
  7. 7. Don’t Cross boundaries
  8. 8. Tools ● ● ● ● SimpleTest atoum PHPT PHPUnit
  9. 9. Installation - Phar $ wget https://phar.phpunit.de/phpunit.phar $ chmod +x phpunit.phar $ mv phpunit.phar /usr/local/bin/phpunit
  10. 10. Installation - Pear pear config-set auto_discover 1 pear install pear.phpunit.de/PHPUnit
  11. 11. Installation - Composer # composer.json { "require-dev": { "phpunit/phpunit": "3.7.*" } } $ composer install
  12. 12. PHPUnit FactorialTest.php <?php class FactorialTest extends PHPUnit_Framework_TestCase { }
  13. 13. public function testSomething() { } /** @test */ public function somethingElse() { }
  14. 14. ● Arrange ● Act ● Assert
  15. 15. Arrange /** @test */ public function factOf1() { $factorial = new Factorial; }
  16. 16. Act /** @test */ public function factOf1() { $factorial = new Factorial; $result = $factorial->fact(1); }
  17. 17. Assert /** @test */ public function factOf1() { $factorial = new Factorial; $result = $factorial->fact(1); $this->assertSame(1, $result); }
  18. 18. PHPUnit Assertions ● ● ● ● ● ● ● $this->assertTrue(); $this->assertEquals(); $this->assertSame(); $this->assertContains(); $this->assertNull(); $this->assertRegExp(); ...
  19. 19. Preparing For Your Tests setup() -> Before every tests teardown() -> After every tests setUpBeforeClass() + tearDownAfterClass() Once per test case
  20. 20. phpunit.xml <phpunit bootstrap="bootstrap.php" colors="true" strict="true" verbose="true" > ... </phpunit>
  21. 21. phpunit.xml <phpunit> <testsuites> <testsuite name="My Test Suite"> <directory>path</directory> <file>path</file> <exclude>path</exclude> </testsuite> </testsuites> </phpunit>
  22. 22. TDD
  23. 23. Red - Green - Refactor Red Write a failing test
  24. 24. Red - Green - Refactor Green Make it pass
  25. 25. Red - Green - Refactor Refactor Fix any shortcuts you took
  26. 26. /** @test */ public function create() { $this->assertNotNull(new Factorial); }
  27. 27. class Factorial { }
  28. 28. /** @test */ public function factOf1() { $facto = new Factorial; $this->assertSame(1, $facto->fact(1)); }
  29. 29. public function fact($number) { return 1; }
  30. 30. Duplication public function create() { $this->assertNotNull(new Factorial); } public function factOf1() { $facto = new Factorial; ...
  31. 31. public function setup() { $this->facto = new Factorial; } /** @test */ public function factOf1() { $this->assertSame(1, $this->facto->fact(1)); }
  32. 32. /** @test */ public function factOf2() { $this->assertSame(2, $this->facto->fact(2)); }
  33. 33. public function fact($number) { return $number; }
  34. 34. More duplication /** @test */ public function factOf1() { $this->assertSame(1, $this->facto->fact(1)); } /** @test */ public function factOf2() { $this->assertSame(2, $this->facto->fact(2)); }
  35. 35. public function factDataProvider() { return array( array(1, 1), array(2, 2), ); }
  36. 36. /** * @test * @dataProvider factDataProvider */ public function factorial($number, $expected) { ...
  37. 37. … $result = $this->facto->fact($number); $this->assertSame($expected, $result); }
  38. 38. public function factDataProvider() { … array(2, 2), array(3, 6), ...
  39. 39. public function fact($number) { if ($number < 2) return 1; return $number * $this->fact($number - 1); }
  40. 40. It’s a lot of work
  41. 41. Dependencies
  42. 42. Problems class Foo { public function __construct() { $this->bar = new Bar; } }
  43. 43. Dependency Injection
  44. 44. Setter Injection class Foo { public function setBar(Bar $bar) { $this->bar = $bar; } public function doSomething() { // Use $this->bar } }
  45. 45. Constructor Injection class Foo { public function __construct( Bar $bar) { $this->bar = $bar; } public function doSomething() { // Use $this->bar } }
  46. 46. Pass the dependency directly class Foo { public function doSomething( Bar $bar) { // Use $bar } }
  47. 47. File System
  48. 48. vfsStream Virtual Files System composer.json "require-dev": { "mikey179/vfsStream": "*" },
  49. 49. Check if a folder was created $root = vfsStream::setup('dir'); $parentDir = $root->url('dir'); //Code creating sub folder $SUT->createDir($parentDir, 'test'); $this->assertTrue( $root->hasChild('test'));
  50. 50. Reading a file $struct = array( 'subDir' => array('test.txt' => 'content') ); $root = vfsStream::setup('root', null, $struct); $parentDir = $root->url('root'); ...
  51. 51. Reading a file … $content = file_get_contents( $parentDir . '/subDir/test.txt'); $this->assertSame('content', $content);
  52. 52. Databases
  53. 53. Mocks Replaces a dependency ● PHPUnit mocks ● Mockery ● Phake
  54. 54. Creation $mock = $this->getMock('NSClass');
  55. 55. Creation $mock = $this->getMock('NSClass'); Or $mock = $this->getMockBuilder ('NamespaceClass') ->disableOriginalConstructor() ->getMock();
  56. 56. $mock->expects($this->once()) ->method('methodName')
  57. 57. $mock->expects($this->once()) ->method('methodName') ->with(1, 'aa', $this->anything())
  58. 58. $mock->expects($this->once()) ->method('methodName') ->with(1, 'aa', $this->anything()) ->will($this->returnValue(10));
  59. 59. Mocking PDO $statement = $this->getMockBuilder ('PDOStatement') ->getMock(); $statement->expects($this->once()) ->method('execute') ->will($this->returnValue(true)); ...
  60. 60. ... $statement->expects($this->once()) ->method('fetchAll') ->will( $this->returnValue( array(array('id' => 123)) ) ); ...
  61. 61. $this->getMockBuilder('PDO') ->getMock();
  62. 62. … $pdo = $this->getMockBuilder( 'stdClass') ->setMethods(array('prepare')) ->getMock(); $pdo->expects($this->once()) ->method('prepare') ->will( $this->returnValue($statement));
  63. 63. class PDOMock extends PDO { public function __construct() {} } $pdo = $this->getMockBuilder ('PDOMock') ->getMock();
  64. 64. mysql_*
  65. 65. DbUnit Extension extends PHPUnit_Extensions_Database_TestCase public function getConnection() { $pdo = new PDO('sqlite::memory:'); return $this-> createDefaultDBConnection( $pdo, ':memory:'); }
  66. 66. public function getDataSet() { return $this-> createFlatXMLDataSet('file'); }
  67. 67. API
  68. 68. ● Wrap all call into a class ○ ZendHttp ○ Guzzle ○ Simple class that uses curl ● Mock the class ○ Return the wanted xml/json
  69. 69. Pros and Cons
  70. 70. Pros ● Less regressions
  71. 71. Pros ● Less regressions ● Trust
  72. 72. Pros ● Less regressions ● Trust ● Low coupling
  73. 73. Pros ● ● ● ● Less regressions Trust Low coupling Simple Design
  74. 74. Cons ● Takes longer
  75. 75. “If it doesn't have to work, I can get it done a lot faster!” - Kent Beck
  76. 76. Cons ● Takes longer ● Can be hard to sell to managers
  77. 77. Cons ● Takes longer ● Can be hard to sell to managers ● It’s hard
  78. 78. Prochaines étapes?
  79. 79. Continuous Testing - Guard
  80. 80. Continuous Integration
  81. 81. Continuous Integration ● Run your tests automatically ○ ○ ○ ○ Unit Tests Acceptance Tests Performance Tests ...
  82. 82. Continuous Integration ● Run your tests automatically ○ ○ ○ ○ Unit Tests Acceptance Tests Performance Tests … ● Check Standards ○ phpcs
  83. 83. Continuous Integration ● Run your tests automatically ○ ○ ○ ○ Unit Tests Acceptance Tests Performance Tests … ● Check Standards ○ phpcs ● Check for "code smells" ○ phpcpd ○ PHP Depend ○ PHP Mess Detector
  84. 84. Questions Twitter: @ehogue Blog: http://erichogue.ca/ Slides: http://www. slideshare.net/EricHogue
  85. 85. Credits ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● Paul - http://www.flickr.com/photos/pauldc/4626637600/in/photostream/ JaseMan - http://www.flickr.com/photos/bargas/3695903512/ mt 23 - http://www.flickr.com/photos/32961941@N03/3166085824/ Adam Melancon - http://www.flickr.com/photos/melancon/348974082/ Zhent_ - http://www.flickr.com/photos/zhent/574472488/in/faves-96579472@N07/ Ryan Vettese - http://www.flickr.com/photos/rvettese/383453435/ shindoverse - http://www.flickr.com/photos/shindotv/3835363999/ Eliot Phillips - http://www.flickr.com/photos/hackaday/5553713944/ World Bank Photo Collection - http://www.flickr.com/photos/worldbank/8262750458/ Steven Depolo - http://www.flickr.com/photos/stevendepolo/3021193208/ Deborah Austin - http://www.flickr.com/photos/littledebbie11/4687828358/ tec_estromberg - http://www.flickr.com/photos/92334668@N07/11122773785/ nyuhuhuu - http://www.flickr.com/photos/nyuhuhuu/4442144329/ Damián Navas - http://www.flickr.com/photos/wingedwolf/5471047557/ Improve It - http://www.flickr.com/photos/improveit/1573943815/
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×