Upload
cyrille-grandval
View
929
Download
0
Embed Size (px)
DESCRIPTION
De nos jours de plus en plus d'entreprises ne jurent que par les tests unitaires. Faire du test, faire du test, faire du test ! “Une application n'est pérenne que si elle est testée et elle est testée si plus de 80% du code est couvert.” Cela devient même un élément décisif du recruteur en entretien : - Votre collaborateur a l'air vraiment bien mais... Il a déjà fait des tests unitaires ? Il a plus de deux ans d'expérience là dessus ? - Juste sur deux projets, par contre il possède la bonne philosophie. - Ah oui mais non il faut qu'il en ait fait 2 ans, c'est un minimum. On cherche des experts nous ! Problématique : "Je veux minimum 80% de couverture de code !!!" Qui n'a pas entendu cette phrase dans la bouche d'un chef de projet ou d'un lead dev trop consciencieux sans doute. Dans certains projets un test unitaire est bon si il couvre au moins 80% de la fonctionnalité à tester, c'est tout ce qui est demandé et c'est cela qu'il faut avoir. Il est avant tout essentiel de s'interroger sur la notion de couverture de code dans un test unitaire : La couverture de code est-elle un but ? un facteur qualité ? une représentation visuelle d'un test ? Ou est-ce cet horrible fantôme qui vient hanter une application ? Pour faire simple : un test qui couvre 100% du code à tester est-il forcement fiable ? Conférence PHPTour Lyon 2014 - Tests unitaires - Je veux mes 80% de couverture de code !!!! http://afup.org/pages/phptourlyon2014/sessions.php#1094
Citation preview
Julien Charpentier – Directeur R&DCyrille Grandval – Directeur Général
Tests Unitaires
« Je veux mes 80% de couverture de code »
24.06.2014PHP Tour Lyon 2014
Qui sommes nous?
Cyrille GrandvalDirecteur général Darkmira
Consultant sécuritéAuteur
[email protected]@CyrilleGrandval
Julien CharpentierDirecteur R&DLead Dev PHP
Auteur
[email protected]@jcharpentier_
Darkmira
Développement PHP sécurisé
Industrialisation
Sécurité Bonnes pratiques
@DarkmiraBrasilwww.darkmira.com.br
@Darkmira1www.darkmira.fr
Historique des tests unitaires
1994 (K.Beck) : SUnit pour SmallTalk
1997 (K.Beck & E.Gamma) : JUnit pour Java
1999 (K.Beck) : XP => TDD
Multiples frameworks créés (xUnit)
Notamment pour PHP : PHPUnit (S.Bergmann)SimpleTest (en fin de vie)Atoum (F.Hardy)
Tests unitaires aujourd’hui…
Préconisés par les techniques de développement logiciel dans lesquels ils sont mis à l’honneur• TDD (Tests Driven Development)• BDD (Behaviour Driven Development)• PDD (Pragmatism Driven Development)
• merci à Gabriel Pillet :)
Dans les esprits :• Pratiqués par les développeurs et attendus par les responsables de projets
Dans la réalité :• Pas le temps• ROI difficilement quantifiable• Armada de tests unitaires obsolètes, en échec mais ignorés• Justification de non écriture systématique• Fausses pistes de recherche de résolution de bugs
Et de plus en plus…
C2DT (Code Coverage Driven Tests)
Je veux au minimum 80% de
couverture de code!!!!!!
Couverture de code : indicateur quantitatif ou qualitatif ?
Extrait de wikipedia“La couverture de code (en anglais code coverage) est une mesure utilisée en génie logiciel pour décrire le taux de code source testé d'un programme. Ceci permet de mesurer la qualité des tests effectués.Car plus un programme est bien testé, moins il est soumis aux bugs.”
Différentes couvertures
Les outils pour PHP nous donne le taux de la couverture des instructions => QUANTITATIF
• Points de tests• Chemins d’exécution
Quantitative• Fonctions• Instructions
Qualitative
100% de couverture de code = application testée ?
Une invitation aux mauvaises pratiquesQue font la plupart des développeurs?
Couverture de code : un trompe l’œil ?
Je test un comportement
Je passe à un test d’un autre
comportement
NON
OUIJ’écris un test
Je vérifie la couverture
>80%
…
Couverture de code : un trompe l’œil ?
class Bar { public function drink($a, $b) { $x = '';
if (1 == $b) { $x .= 'B'; } else { $x .= 'E'; }
if (1 == $b) { $x .= 'R'; } else { $x .= 'E'; }
return $x; }}
class BarTest extends PHPUnit_Framework_TestCase{ protected function setUp() { parent::setUp (); $this->Bar = new Bar(); }
public function testBar() { $sDrink = $this->Bar->drink(1, 2); $this->assertEquals('BE', $sDrink);
$sDrink = $this->Bar->drink(2, 1); $this->assertEquals('ER', $sDrink); }}
Représentation graphique
Couverture de code : un trompe l’œil ?
Instructions : 100%Chemins d’exécution : 50%
Représentation graphique
Couverture de code : un trompe l’œil ?
Couverture de code : un trompe l’œil ?
100% de couverture de code = application testée
N’assure pas que :• Des assertions sont présentes• Qu’elles testent les bons comportements• Que les tests soient vraiment unitaires• Que le test soit lisible et bien écrit• Que les cas d’entrée soient clairement identifiés
Que le test soit un test unitaire
Couverture de code : conséquences
Une plaie pour les développeurs• Ils ne comprennent pas l’utilité• Ils ne comprennent pas comment écrire les tests• Ils ont l’impression de perdre leur temps
C’est inutile et contre-productif• Laisser-aller• Incompréhension• Perte de temps• Builds trop longs
Une bombe à retardement• Coûts de développement trop élevés• Coûts de maintenance trop élevés• Perte de confiance• TU obsolètes et ignorés• Application vulnérable
Couverture de code : conséquences
C’est un risque bien réel
C2DT : Tue la politique de tests unitairesOutils pas assez matures pour PHPIndicateur uniquement quantitatifN’atteste pas de la qualité des tests unitaires => La vérité est ailleurs
80% !???
LE CODE DE TEST N’EST PAS QUE DU CODE
DE TEST !!!
La qualité à l’état naturel
• Philosophie• Bonnes pratiqueso Conventionso Lisibilitéo Commentaires
• Bons outils
La qualité à l’état naturel : Intro
Qu’est ce qu’un test unitaire ?• Un test unitaire consiste à isoler un comportement de tout facteur extérieur et de vérifier qu’il est conforme à ce que vous attendez.
Pourquoi teste-t-on ?• Vérifier
Quels sont les avantages ?
• Documenter• Automatiser
Sérénité
Ne plus avoir peur de modifier le code
Comprendre un code que l’on n’a pas écrit
Supprimer du code sans perdre de fonctionnalité
Facilité de la maintenance
S’assurer de la non régression
La qualité à l’état naturel : Philosophie
Coder en pensant test…• Coder l’application pour qu’elle soit naturellement et unitairement testable• Veiller à garder un couplage faible• Utiliser l’injection de dépendance• Veiller à limiter la complexité cyclomatique• Faire des revues de codes ou du pair programming• Ne pas propager un code qui peut-être refactorisé
…et tester en pensant qualité de la couverture• Rechercher le taux de couverture des chemins d’exécution le plus haut possible• Tester en boîte blanche
o Identifier et tester toutes les entrées possibles…o …et vérifier les sorties attendues correspondantes
• Ne pas se limiter aux cas simpleso Tester les cas nominaux…o …mais aussi les cas en erreur et les cas limites
La qualité à l’état naturel : Bonnes pratiques
10 règles à respecter
• Un test unitaire doit-être UNITAIRE !• Utilisez les mocks et/ou stubs (100% des appels externes)• Un test est avant tout du code : il doit simple, normé, commenté, facile à lire et à
comprendre • Un test doit être rapide à exécuter• Les tests doivent être écrits le plus tôt possible• Un test = une assertion (ou presque)• Testez en priorité les parties critiques de l’application• Écrivez le code de l’application pour qu’il soit testable• Refactorisez !• Le nom d’un test est capital, normalisez le !
ex: testNomMethode_EtatDepart_ComportementAttendu donnera testOpenFile_FileNoExists_ThrowException()
La qualité à l’état naturel : Bonnes pratiques
10 règles à respecter
• Un test unitaire doit-être UNITAIRE !• Utilisez les mocks et/ou stubs (100% des appels externes)• Un test est avant tout du code : il doit simple, normé, commenté, facile à lire et à
comprendre • Un test doit être rapide à exécuter• Les tests doivent être écrits le plus tôt possible• Un test = une assertion (ou presque)• Testez en priorité les parties critiques de l’application• Écrivez le code de l’application pour qu’il soit testable• Refactorisez !• Le nom d’un test est capital, normalisez le !
La qualité à l’état naturel : Bonnes pratiques
10 règles à respecter
• Un test unitaire doit-être UNITAIRE !• Utilisez les mocks et/ou stubs (100% des appels externes)• Un test est avant tout du code : il doit simple, normé, commenté, facile à lire et à
comprendre • Un test doit être rapide à exécuter• Les tests doivent être écrits le plus tôt possible• Un test = une assertion (ou presque)• Testez en priorité les parties critiques de l’application• Écrivez le code de l’application pour qu’il soit testable• Refactorisez !• Le nom d’un test est capital, normalisez le !
La qualité à l’état naturel : Bonnes pratiques
10 règles à respecter
• Un test unitaire doit-être UNITAIRE !• Utilisez les mocks et/ou stubs (100% des appels externes)• Un test est avant tout du code : il doit simple, normé, commenté, facile à lire et à
comprendre • Un test doit être rapide à exécuter• Les tests doivent être écrits le plus tôt possible• Un test = une assertion (ou presque)• Testez en priorité les parties critiques de l’application• Écrivez le code de l’application pour qu’il soit testable• Refactorisez !• Le nom d’un test est capital, normalisez le !
La qualité à l’état naturel : Bonnes pratiques
10 règles à respecter
• Un test unitaire doit-être UNITAIRE !• Utilisez les mocks et/ou stubs (100% des appels externes)• Un test est avant tout du code : il doit simple, normé, commenté, facile à lire et à
comprendre • Un test doit être rapide à exécuter• Les tests doivent être écrits le plus tôt possible• Un test = une assertion (ou presque)• Testez en priorité les parties critiques de l’application• Écrivez le code de l’application pour qu’il soit testable et refactorisez !• Utiliser les design pattern (ex : AAA)• Le nom d’un test est capital, normalisez le !
test[NomMethode][EtatDeDepart][ComportementAttendu]
10 pièges à éviter
• Avoir pour but la couverture de code :)• Écrire un test illisible• Écrire un test non isolé
o dépendant de facteurs extérieurs (temps)o dépendant de l'environnement (système de fichiers, base de données,
webservices, ...)o dépendant d’un autre test
• Écrire les tests quand on a le temps• Décorréler le test et le code testé
o Ecrire un test sans comprendre le comportement testéo Écrire un test sans refactoriser un code qui doit l’être
• Confondre test unitaire et test d’intégration• Ne pas exécuter les TU à chaque commit / push sur le dépot• Écrire un test par comportement testé• Ecrire un test gérant plusieurs états• Faire trop de tests unitaires !
La qualité à l’état naturel : Mauvaises pratiques
10 pièges à éviter
• Avoir pour but la couverture de code :)• Écrire un test illisible• Écrire un test non isolé
o dépendant de facteurs extérieurs (temps)o dépendant de l'environnement (système de fichiers, base de données,
webservices, ...)o dépendant d’un autre test
• Écrire les tests quand on a le temps• Décorréler le test et le code testé
o Ecrire un test sans comprendre le comportement testéo Écrire un test sans refactoriser un code qui doit l’être
• Confondre test unitaire et test d’intégration• Ne pas exécuter les TU à chaque commit / push sur le dépot• Écrire un test par comportement testé• Ecrire un test gérant plusieurs états• Faire trop de tests unitaires !
La qualité à l’état naturel : Mauvaises pratiques
10 pièges à éviter
• Avoir pour but la couverture de code :)• Écrire un test illisible• Écrire un test non isolé
o dépendant de facteurs extérieurs (temps)o dépendant de l'environnement (système de fichiers, base de données,
webservices, ...)o dépendant d’un autre test
• Écrire les tests quand on a le temps• Décorréler le test et le code testé
o Ecrire un test sans comprendre le comportement testéo Écrire un test sans refactoriser un code qui doit l’être
• Confondre test unitaire et test d’intégration• Ne pas exécuter les TU à chaque commit / push sur le dépot• Écrire un test par comportement testé• Ecrire un test gérant plusieurs états• Faire trop de tests unitaires !
La qualité à l’état naturel : Mauvaises pratiques
10 pièges à éviter
• Avoir pour but la couverture de code :)• Écrire un test illisible• Écrire un test non isolé
o dépendant de facteurs extérieurs (temps)o dépendant de l'environnement (système de fichiers, base de données,
webservices, ...)o dépendant d’un autre test
• Écrire les tests quand on a le temps• Décorréler le test et le code testé
o Ecrire un test sans comprendre le comportement testéo Écrire un test sans refactoriser un code qui doit l’être
• Confondre test unitaire et test d’intégration• Ne pas exécuter les TU à chaque commit / push sur le dépot• Écrire un test par comportement testé• Ecrire un test gérant plusieurs états• Faire trop de tests unitaires !
La qualité à l’état naturel : Mauvaises pratiques
Tester la qualité : le Mutation Testing
Tester le test lui-même
Un peu d’histoire
• 1971 (Richard Lipton) – Concept
• 1980 (Timothy Budd) - Premier outil
• Constat : Les tests vérifient que l’application est l'implémentation correcte des besoins. Sont-ils suffisamment qualifiés ? Repèrent-t-ils un dysfonctionnement ?
• Objectif : Créer des mutations simples du code source d’une application et soumettre ces mutations à la suite de tests unitaires.
• Score qualitatif = nombre de mutants tués / nombre de mutants créés
Tester la qualité : le Mutation Testing
Fonctionnement
• Le mutation-testing utilise un lot de mutations simples qu’il applique une à une sur le code source original de l’application.
• Il crée ainsi des mutations du code original qui en modifie son comportement.
• Ce comportement étant différent, certains tests devraient logiquement le repérer et ne plus être acceptés
• Exemples de mutations :o modification de conditions (== par !=, == par =, && par ||, > par <, etc.)o modification structurelles (suppression de bloc else, d’un case de switch, etc.)o modification de valeurs (true par false, …)
Tester la qualité : le Mutation Testing
Tester la qualité : le Mutation Testing
Exemple 1
if ($a && $b) { $c = 1;} else { $c = 0;}
L’opérateur de condition && va être remplacé
par ||
if ($a || $b) { $c = 1;} else { $c = 0;}
Si $a = true et $b = false, le comportement est différent du code original, $c sera égal
à 1 au lieu d’être à 0.Un test unitaire va-t-il
repérer cela ?
Tester la qualité : le Mutation Testing
Exemple 2
if ($a && $b) { $c = 1;} else { $c = 0;}
Le bloc else va être supprimé
if ($a && $b) { $c = 1;}
Si $a et/ou $b sont égaux à false, le comportement est
différent du code original, $c ne sera pas défini au lieu d’être
égal à 0.Un test unitaire va-t-il repérer
cela ?
Tester la qualité : le Mutation Testing
Ce qui impose donc au test, pour tuer le mutant :• de couvrir l’instruction mutante• de prendre en compte l’entrée qui donne vie au mutant• d’être capable de vérifier que la sortie mutante n’est pas attendue
et impose au code, de propager la ou les valeurs mutantes en sortie.
Cela vérifie donc bien :• la couverture des instructions• la couverture des chemins d’exécution• la couverture des points de tests• la couverture des E/S
Tester la qualité : le Mutation Testing
Outils pour PHP• 2013 (Jean-François Lépine) MutaTesting
o PHP 5.3+o Ne nécessite pas d’extensiono Indépendant du framework de testso Ne nécessite pas de code en pluso Intégrable facilement dans un outil d’intégration continue (type Jenkins)o Ne crée pas les mutants physiquement
(Source : https://github.com/Halleck45/MutaTesting/)
Des questions???
Merci !