Commencer avec le tdd

Post on 24-Jun-2015

7.260 views 1 download

description

Le TDD (Test Driven Development) devient de plus en plus populaire. Guider le développement d’une application par les tests est maintenant une pratique acceptée dans plusieurs communautés. Mais démarrer avec le TDD peut être une tâche ardue. Dans cette présentation, nous allons voir ce qu’est le TDD. En commençant par les principes fondamentaux au TDD. Puis nous verrons quels sont les outils utilisés. Puis comment appliquer ces techniques dans le travail quotidien.

Transcript of Commencer avec le tdd

Commencer avec le TDDEric Hogue

PHP Québec - 2013-06-06

Test Driven Development

Où Commencer?

Les tests unitaires

Test automatisé qui exerce une seule unité de code

Outils

● PHPUnit● SimpleTest● atoum● PHPT

PHPUnit

FactorialTest.php<?phpclass FactorialTest extends \PHPUnit_Framework_TestCase {}

public function testSomething() {}

/** @test */public function somethingElse() {}

Les assertions

● $this->assertTrue();● $this->assertEquals();● $this->assertSame();● $this->assertContains();● $this->assertNull();● $this->assertRegExp();● ...

Préparation des tests

setup() -> Avant chaque testteardown() -> Après chaque test

phpunit.xml

<phpunit bootstrap="bootstrap.php" colors="true"strict="true"verbose="true"

>...

</phpunit>

Le TDD

nyuhuhuuhttp://www.flickr.com/photos/nyuhuhuu/4442144329/

Red - Green - Refactor

Rouge Un test qui échoue

Red - Green - Refactor

VertFaire passer le test

Red - Green - Refactor

RefactorArranger le code

/** @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 Factorial;

...

public function setup() {$this->facto = new Factorial;

}/** @test */public function factOf1() {

$this->assertSame(1, $this->facto->fact(1));}

/** @test */public function factOf2() {

$this->assertSame(2, $this->facto->fact(2));}

public function fact($number) {return $number;

}

Encore de la duplication

/** @test */public function factOf1() {

$this->assertSame(1, $this->facto->fact(1));}/** @test */public function factOf2() {

$this->assertSame(2, $this->facto->fact(2));}

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);

}

array(3, 6,),

array(3, 6,),

public function fact($number) {if ($number < 2) return 1;return $number * $this->fact($number - 1);

}

Les 3 lois du TDD selon Uncle Bob

● Ne jamais écrire du code de production sauf pour faire passer un test unitaire qui échoue

http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

Les 3 lois du TDD selon Uncle Bob

● Ne jamais écrire du code de production sauf pour faire passer un test unitaire qui échoue

● Ne pas écrire plus de test que nécéssaire pour avoir un échec○ une erreur de compilation est un échec

http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

Les 3 lois du TDD selon Uncle Bob

● Ne jamais écrire du code de production sauf pour faire passer un test unitaire qui échoue

● Ne pas écrire plus de test que nécéssaire pour avoir un échec○ une erreur de compilation est un échec

● Ne pas écrire plus de code de production que nécéssaire pour faire passer le test unitaire

http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

Beaucoup de travail

Photo: Adam Melanconhttp://www.flickr.com/photos/melancon/348974082/

Les dépendances

Zhent_http://www.flickr.com/photos/zhent/574472488/in/faves-96579472@N07/

Les fichiers

Ryan Vettesehttp://www.flickr.com/photos/rvettese/383453435/

vfsStream

Système de fichier virtuel

composer.json"require-dev": {

"mikey179/vfsStream": "*"},

Vérifier la création d'un répertoire

$root = vfsStream::setup('dir');$parentDir = $root->url('dir');

//Code qui créer un sous répertoire$this->createDir($parentDir, 'test');

$this->assertTrue($root->hasChild('test'));

Lire un fichier

$struct = array('subDir' => array('test.txt' => 'contenu')

);$root = vfsStream::setup('root', null, $struct);$parentDir = $root->url('root');

$content = file_get_contents($parentDir . '/subDir/test.txt');$this->assertSame('contenu' , $content);

La base de données

shindoversehttp://www.flickr.com/photos/shindotv/3835363999/

Les Mocks

Permet de remplacer une dépendance

● PHPUnit mocks● Mockery● Phake

Création

$mock = $this->getMock('\Namespace\Classe');

Création

$mock = $this->getMock('\Namespace\Classe');

Ou

$mock =$this->getMockBuilder ('\Namespace\Classe') ->disableOriginalConstructor() ->getMock();

$mock->expect($this->once()) ->method('nomMéthode')

$mock->expect($this->once()) ->method('nomMéthode') ->with(1, 'aa', $this->anything())

$mock->expect($this->once()) ->method('nomMéthode') ->with(1, 'aa', $this->anything()) ->will($this->returnValue(10));

PDO

$statement = $this->getMockBuilder('\PDOStatement')

->getMock();$statement->expects($this->once())

->method('execute')->will($this->returnValue(true));

$statement->expects($this->once())->method('fetchAll')->will($this->returnValue(array(array('id' =>

123, 'name' => 'Eric Hogue'))));

$pdo = $this->getMockBuilder('\stdClass')->disableOriginalConstructor()->setMethods(array('prepare'))->getMock();

$pdo->expects($this->once())->method('prepare')->will($this->returnValue($statement));

Pour utiliser PDO

$this->getMockBuilder('\PDO')

class PDOMock extends \PDO { public function __construct() {}

}

$pdo = $this->getMockBuilder('\PDOMock')->getMock();

mysql_*

Eliot Phillipshttp://www.flickr.com/photos/hackaday/5553713944/

L'extension DbUnit

extends PHPUnit_Extensions_Database_TestCase

public function getConnection() { $pdo = new PDO('sqlite::memory:');

return $this->createDefaultDBConnection($pdo, ':memory:');

}

public function getDataSet() {return $this->createFlatXMLDataSet('file');

}

API

● Mettre tous les appels HTTP dans une classe○ Zend\Http○ Simple classe qui appel curl

● Faire un mock de cette classe○ Retourne le xml/json voulu

Avantages - Inconvénients

Avantages du TDD

● Moins de régression

Avantages du TDD

● Moins de régression● Plus de confiance

Avantages du TDD

● Moins de régression● Plus de confiance● Couplage plus faible

Avantages du TDD

● Moins de régression● Plus de confiance● Couplage plus faible● Design plus simple

Inconvénients du TDD

● Plus long

“If it doesn't have to work, I can get it done a lot faster!”- Kent Beck

Improve Ithttp://www.flickr.com/photos/improveit/1573943815/

Inconvénients du TDD

● Plus long● Difficile à vendre aux gestionnaires

Inconvénients du TDD

● Plus long● Difficile à vendre aux gestionnaires● C'est difficile

Prochaines étapes?

Continuous Testing

BDD

● phpspec● Codeception● Behat

○ Mink + Goutte/Selenium

Behat + Mink

Feature: Add a new postIn order to post the next meetupAs an admin userI want to add a new event

Scenario: View eventsGiven I am on "/"When I go to "evenement"Then I should see "Commencer avec le

TDD"

Intégration Continue

Intégration Continue

● Exécute les tests automatiquement○ tests unitaires○ tests d'acceptation○ tests de performace ○ ...

Intégration Continue

● Exécute les tests automatiquement○ tests unitaires○ tests d'acceptation○ tests de performace ○ ...

● Vérifie que les standards sont respectés○ phpcs

Intégration Continue

● Exécute les tests automatiquement○ tests unitaires○ tests d'acceptation○ tests de performace ○ ...

● Vérifie que les standards sont respectés○ phpcs

● Détecte des "code smells"○ phploc○ phpcpd○ PHP Depend○ PHP Mess Detector

Damián Navashttp://www.flickr.com/photos/wingedwolf/5471047557/

Commentaires:https://joind.in/8740

Twitter:@ehogue

Blogue:http://erichogue.ca/

Questions