Commencer avec le TDD
Eric Hogue - @ehogue
Confoo - 2014-02-27
1
TDD
2
Où commencer?
3
Tests unitaires
4
Tests unitaires
est une procédure permettant de vérifier le bon
fonctionnement d'une partie précise d'un
logiciel ou d'une portion d'un programme
(appelée « unité » ou « module »).
http://fr.wikipedia.org/wiki/Test_unitaire
5
Ne pas traverser de frontières
6
Outils
● SimpleTest
● atoum
● PHPT
● PHPUnit
7
8
Installation - Phar
$ wget
https://phar.phpunit.de/phpunit.phar
$ chmod +x phpunit.phar
$ mv phpunit.phar /usr/local/bin/phpunit
9
Installation - Composer
# composer.json
{
"require-dev": {
"phpunit/phpunit": "4.5.*"
}
}
$ composer install
10
PHPUnit
FactorialTest.php
<?php
class FactorialTest extends
PHPUnit_Framework_TestCase {
}
11
public function testSomething() {
}
/** @test */
public function somethingElse() {
}
12
● Arrange
● Act
● Assert
13
Arrange
/** @test */
public function factOf1() {
$factorial = new Factorial;
}
14
Act
/** @test */
public function factOf1() {
$factorial = new Factorial;
$result = $factorial->fact(1);
}
15
Assert
/** @test */
public function factOf1() {
$factorial = new Factorial;
$result = $factorial->fact(1);
$this->assertSame(1, $result);
}
16
PHPUnit Assertions
● $this->assertTrue();
● $this->assertEquals();
● $this->assertSame();
● $this->assertContains();
● $this->assertNull();
● $this->assertRegExp();
● ...
17
Preparing For Your Tests
setup() -> Avant chaque test
teardown() -> Après chaque test
setUpBeforeClass() + tearDownAfterClass()
Une fois par test
18
19
TDD
20
3 règles du TDD - Uncle Bob
● You are not allowed to write any production
code unless it is to make a failing unit test
pass.
● You are not allowed to write any more of a
unit test than is sufficient to fail;
○ and compilation failures are failures.
● You are not allowed to write any more
production code than is sufficient to pass the
one failing unit test.
http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
21
Red - Green - Refactor
Red
Écrire un test qui échoue
22
Red - Green - Refactor
Green
Le faire passer
23
Red - Green - Refactor
Refactor
Régler les raccourcis pris
24
/** @test */
public function create() {
$this->assertNotNull(new Factorial);
}
25
class Factorial {
}
26
/** @test */
public function factOf1() {
$facto = new Factorial;
$this->assertSame(1,
$facto->fact(1));
}
27
public function fact($number) {
return 1;
}
28
Duplication
public function create() {
$this->assertNotNull(new Factorial);
}
public function factOf1() {
$facto = new Factorial;
...
29
public function setup() {
$this->facto = new Factorial;
}
/** @test */
public function factOf1() {
$this->assertSame(1,
$this->facto->fact(1));
}
30
/** @test */
public function factOf2() {
$this->assertSame(2,
$this->facto->fact(2));
}
31
public function fact($number) {
return $number;
}
32
Plus de duplication
/** @test */
public function factOf1() {
$this->assertSame(1,
$this->facto->fact(1));
}
/** @test */
public function factOf2() {
$this->assertSame(2,
$this->facto->fact(2));
} 33
public function factDataProvider() {
return [
[1, 1],
[2, 2],
];
}
34
/**
* @test
* @dataProvider factDataProvider
*/
public function factorial($number,
$expected) {
...
35
…
$result =
$this->facto->fact($number);
$this->assertSame($expected,
$result);
}
36
public function factDataProvider() {
…
[2, 2],
[3, 6],
...
37
public function fact($number) {
if ($number < 2) return 1;
return $number *
$this->fact($number - 1);
}
38
Beaucoup
de travail
39
40
Dépendances
41
Problème
class Foo {
public function __construct() {
$this->bar = new Bar;
}
}
42
Injection des dépendances
43
Setter Injection
class Foo {
public function setBar(Bar $bar) {
$this->bar = $bar;
}
}
public function doSomething() {
// Use $this->bar
}
44
Constructor Injection
class Foo {
public function __construct(
Bar $bar) {
$this->bar = $bar;
}
...
}
45
Passer la dépendance aux méthodes
class Foo {
public function doSomething(
Bar $bar) {
// Use $bar
}
}
46
Système de fichiers
47
vfsStream
Système de fichier virtuel
composer.json
"require-dev": {
"mikey179/vfsStream": "*"
},
48
Vérifier la création d’un répertoire
$root = vfsStream::setup('dir');
$parentDir = $root->url('dir');
//Code creating sub folder
$SUT->createDir($parentDir, 'test');
$this->assertTrue(
$root->hasChild('test'));
49
Lire un fichier
$struct = [
'subDir' => ['test.txt'
=> 'content']
];
$root = vfsStream::setup('root',
null, $struct);
$parentDir = $root->url('root');
...
50
Lire un fichier
…
$content = file_get_contents(
$parentDir . '/subDir/test.txt');
$this->assertSame('content',
$content);
51
Base de données
52
Mocks
Remplace une dépendance
● PHPUnit mocks
● Mockery
● Phake
53
Création
$mock = $this->getMock('NSClass');
$mock = $this->getMockBuilder
('NamespaceClass')
->disableOriginalConstructor()
->getMock();
54
$mock->expects($this->once())
->method('methodName')
55
$mock->expects($this->once())
->method('methodName')
->with(1, 'aa', $this->anything())
56
$mock->expects($this->once())
->method('methodName')
->with(1, 'aa', $this->anything())
->will($this->returnValue(10));
57
Mocking PDO
$statement = $this->getMockBuilder
('PDOStatement')
->getMock();
$statement->expects($this->once())
->method('execute')
->will($this->returnValue(true));
...
58
...
$statement->expects($this->once())
->method('fetchAll')
->will(
$this->returnValue(
[['id' => 123]]
)
);
...
59
$this->getMockBuilder('PDO')
->getMock();
60
…
$pdo = $this->getMockBuilder(
'stdClass')
->setMethods(['prepare'])
->getMock();
$pdo->expects($this->once())
->method('prepare')
->will(
$this->returnValue($statement));
61
class PDOMock extends PDO {
public function __construct() {}
}
$pdo = $this->getMockBuilder
('PDOMock')
->getMock();
62
mysql_*
63
DbUnit
extends
PHPUnit_Extensions_Database_TestCase
public function getConnection() {
$pdo = new PDO('sqlite::memory:');
return $this->
createDefaultDBConnection(
$pdo, ':memory:');
}
64
public function getDataSet() {
return $this->
createFlatXMLDataSet('file');
}
65
API
66
● Encapsuler
○ ZendHttp
○ Guzzle
○ Classe qui utilise curl
● Mock
○ Retourner le xml/json voulu
67
Avantages et inconvénients
68
Avantages
69
Inconvénients
70
“If it doesn't have to
work, I can get it done a
lot faster!”
- Kent Beck
71
Inconvénients
72
Prochaines étapes?
73
Tests en continue - Guard
74
Intégration continue
75
Commentaires: https://joind.in/13312
twitter: @ehogue
PHP Mentoring: http://phpmentoring.org/
Questions?
76
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/
● PolliceVersoThumbsUp.jpg - keimevo - https://www.flickr.com/photos/keimevo/14093768567/in/photostream/
● PolliceVersoThumbsDown.jpg - keimevo - https://www.flickr.com/photos/keimevo/14093716370/in/photostream/
● CILights.jpg - Jan Krutisch - https://www.flickr.com/photos/jankrutisch/4272142306/in/photostream/
77

Commencer avec le TDD