Tests Driven Developments
(aka TDD)
Thierry GAYET
❑ Introduction
❑ Méthodes traditionnelles et tests
❑ Impacts et coût des défauts
❑ Test Driven Development
❑ Définition
❑ Méthodologie
❑ Avantages, inconvénients
❑ Injection de dépendances, fakes et mocks
❑ Exemple
❑ Expérience personnelle
Introduction
2
Introduction
❑ Le code logiciel est fragile
❑ Quasiment n’importe quel changement peut avoir des conséquences
inattendues
❑ Le but de cette présentation est de montrer une méthode de
développement qui permet d'améliorer la qualité logiciel, et de réduire
les coûts de développement
❑ Grâce à cette méthode, nous pourrons à tout moment nous assurer de la
maturité du logiciel, et être immédiatement averti de toute déviation,
régression ou défaut, et ce dès leur introduction dans le code.
Programmation Pilotée par les Tests
=
Test Driven Development
Introduction
4
Méthodes traditionnelles : waterfall
5
User
requirements
Functional
specification
s
Global
technical
design
Detailed
technical
design
Programming
Testing CODE DRIVEN
DEVELOPMENT
Méthodes traditionnelles : cycle en
V
6
User
requirement
s
Functional
specification
s
Global
technical
design
Detailed
technical
design
Programming
Component
tests
Integration
tests
System tests
Acceptance
tests
❑ Lorsque les tests ne sont pas automatisés, éventuellement seuls les tests que l’on pense
être nécessaires seront utilisés
❑ Parfois seulement des tests fonctionnels sont utilisés (surtout en waterfall), rendant
souvent impossible le test des gestions d’erreurs
❑ Les tests unitaires (si existants) sont ajoutés après la phase de codage
❑ Couverture de code non complète
❑ Tout le code n’est pas testable (couplage fort entre interfaces)
❑ Tendre vers 100% de couverture demande un effort exponentiel
❑ On ne connaît pas la maturité du code avant les phases de test (et les résultats peuvent
être trompeurs)
Méthodes traditionnelles & tests
7
Méthodes traditionnelles & tests
8
❑ La détection des défauts intervient bien après la phase de codage
❑ Tous les défauts ne peuvent pas être découverts
❑ Un bug simple peut n’être découvert que très tard
❑ Plus un bug est trouvé tard, plus il est coûteux à fixer
❑ La qualité d’un logiciel ne se mesure pas seulement dans son comportement ni dans
ses performances
❑ Le code doit être maintenable, donc simple à comprendre
❑ Conséquences :
❑ Aucune ou peu de confiance dans la maturité du code
❑ Le projet prend du retard
❑ Les coûts ne sont pas maîtrisés
Méthodes traditionnelles : coût des
défauts
9
Source : Software Engineering Economics, B.W. Boehm, 1981
Exemple de bug couteux
10
❑ Ariane 5 – Juin 1996
o Un bug du logiciel de la fusée provoqua son autodestruction :
o Récupération du soft Ariane 4 : accélération codée sur 8 bit
o Sur Ariane 5 (accélération plus grande) => dépassement de capacité (9
bits auraient été nécessaires)
o Les pertes sont estimées à un total de 370 millions de dollars.
o http://fr.wikipedia.org/wiki/Vol_501_d%27Ariane_5
❑ Therac-25
o Machine de radiothérapie, évolution des modèles précédents
o Entre 1985 et 1987, des patients reçurent des doses massives de radiation,
au moins cinq patients décédèrent.
o Plusieurs problèmes de gestion du projet informatique furent découverts
après enquête, dont des tests logiciels incomplets.
o http://fr.wikipedia.org/wiki/Therac-25
Tests unitaires : pas suffisant !
11
Code testé :
int checksum(void *p, int len)
{
int sum = 0;
unsigned char* pp = (unsigned char*)p;
int i;
for (i = 0; i <= len; i++)
{
sum += *pp++;
}
return sum;
}
❑ Test unitaire :
char *myString = "foo";
assert(324 == checksum(myString, strlen(myString)));
❑ Couverture incomplète : bug potentiel non détecté !
Le problème avec cette fonction
checksum est dans la boucle for. La
condition i <= len doit être corrigée
pour i < len, car sinon, la boucle
parcourra un octet de plus que la
longueur réelle de la chaîne, ce qui
entraînera un dépassement de
mémoire tampon et un
comportement indéfini. De plus,
vous devriez utiliser un type de
donnée plus grand pour stocker la
somme, comme unsigned int, pour
éviter un débordement de la somme
en cas de longues chaînes.
❑ Code testé :
void checkRange(int i, int j)
{
if (i >= 3) throw std::exception("out of range");
if (j >= 3) throw std::exception("out of range");
}
❑ Test unitaire : 100% de couverture
EXPECT_THROW(checkRange(0, 3))
EXPECT_THROW(checkRange(3, 0))
❑ Mais supposons qu’un nombre négatif ne
soit pas admis :
checkRange(-1, 2);
Tests unitaires : pas suffisant !
12
Le problème principal avec cette fonction est qu'elle utilise std::exception
de manière incorrecte. std::exception est une classe de base pour toutes
les exceptions standard C++, mais elle n'a pas de constructeur qui prend
une chaîne de caractères comme argument.
Pour créer une exception personnalisée avec un message, vous devez
définir votre propre classe d'exception dérivée de std::exception et fournir
un constructeur prenant une chaîne de caractères comme argument.
EXPECT_THROW(checkRange(0, 3), std::out_of_range);
EXPECT_THROW(checkRange(3, 0), std::out_of_range);
try {
checkRange(-1, 2);
} catch (const std::out_of_range& e) {
// Gérer l'exception ici
}
Cette correction permet à la fonction checkRange de lancer une exception
std::out_of_range avec un message spécifique lorsque les valeurs i ou j
sont en dehors de la plage spécifiée.
❑ TDD est une méthode de développement incrémental
❑ Le principe :
o En testant en premier, je conçois le code
❑ La méthode :
o Aucun code n’est implémenté avant d’avoir écrit un test unitaire qui échoue
o Ensuite, le code est implémenté, le test unitaire réussi
❑ Origine :
o eXtreme Programming (XP)
o 1999 Kent Beck, Martin Fowler et autres…
❑ Souvent utilisé dans un cycle Agile, mais ce n’est pas obligatoire !
❑ Très orienté DEVSECOPS avec des cycles CI/CD !
TDD
13
TDD
14
❑ TDD inverse la méthode classique de codage en premier et debug plus tard
❑ TDD implique que le développeur d’un module se concentre donc dès le début sur :
o Son interface : comment vais-je l’utiliser ?
o Son comportement : que fait-il ?
o Sa réutilisation : clients multiples du code et des tests
o Ses dépendances : il doit être testé de façon isolée
o Sa cohésion : un module testable a une raison d’être
❑ Les détails d’implémentation sont secondaires
❑ Ceci encourage le découplage des interfaces
o Code plus modulaire
o Un système découplé est plus évolutif
❑ Chaque ajout de code aura un test ou des tests correspondant
Commencer par écrire des tests ?
15
Tests unitaires pour tester :
- ses classes
- ses API privées
- ses API publiques
❑ L’automatisation des tests est un élément clé de TDD
o Continuous Integration (aka CI)
❑ Les tests sont simples
❑ A chaque étape du développement, de nouveaux tests sont ajoutés, suivi de
l’implémentation
❑ A chaque changement introduit dans du code existant, les tests sont exécutés
o Test du nouveau code
o Test du code existant
❑ Toute régression est ainsi immédiatement trouvée et est facile à corriger
Automatisation
16
Coûts des défauts
17
Bug introduit Bug
découvert
Cause
trouvée
Correction
Bug introduit
Bug
découvert
Cause
trouvée
Correction
❑ Traditionnelleme
nt :
❑ Avec TDD :
Parallélisation, réduction des temps d’action !
❑ Meilleure couverture de test (but : 100%)
❑ Moins de défauts, moins d’effets de bord, moins de temps passé à debugger
❑ Le code est conçu de façon à être plus facile à tester
❑ Code plus modulaire
❑ Design plus propre et plus facile à comprendre
❑ La refactorisation devient plus facile
❑ Les tests constituent une documentation bas-niveau
o Pour chaque feature, il y a au moins un exemple d’utilisation
o Toujours à jour !
TDD : avantages
18
❑ TDD ne garantie pas une bonne architecture ou design
❑ TDD est plus difficile à utiliser dans les situations où des tests fonctionnels sont requis
pour déterminer le succès ou l'échec
o Interfaces homme-machine
o Base de données
o Réseaux
❑ Le support du management est essentiel
o Sans l’entière organisation convaincue que TDD va améliorer le produit, le temps
passé à écrire les tests est souvent vu comme perdu
❑ Les tests sont typiquement écrits par le développeur du code testé
❑ TDD ne remplace pas les autres activités de test (intégration, validation, conformité,
etc)
TDD : vulnérabilités
19
❑ Bob Martin décrit TDD avec trois règles simples :
o Do not write production code unless it is to make a failing unit test pass ;
o Do not write more of a unit test than is sufficient to fail, and build failures are
failures ;
o Do not write more production code than is sufficient to pass the one failing unit test.
http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
TDD : les trois lois
20
TDD : microcycle
21
❑ Les tests montrent que le comportement est correct : le code fonctionne
❑ Mais du code doit être propre et bien structuré
o Plus facile à comprendre
o Plus facile à faire évoluer
o Plus facile à maintenir
❑ C’est le but de la dernière étape du microcycle
❑ La refactorisation est l’activité de changer la structure d’un code sans en changer son
comportement
❑ Souvent appelé « Red-Green-Refactor »
TDD : refactorisation
22
TDD : microcycle
23
Exemple avec une classe en C++
TDD : exemple
25
⮚Test :
#include <assert.h>
#include "quad.h"
int main()
{
Quad q;
assert(6 == q.area(2, 3));
return 0;
}
⮚Code :
• Le test ne compile pas car le code est inexistant !
TDD : exemple
26
⮚Test :
#include <assert.h>
#include "quad.h"
int main()
{
Quad q;
assert(6 == q.area(2, 3));
return 0;
}
⮚Code :
class Quad {
public:
Quad () {;}
int area(int w, int h) { return
6; }
};
→ Cette fonction a pour but de
calculer l’aire d’un quadilatère.
• Le test compile et réussi !
TDD : exemple
27
⮚Test :
#include <assert.h>
#include "quad.h"
int main()
{
Quad q;
assert(6 == q.area(2, 3));
return 0;
}
⮚Code :
class Quad {
public:
Quad () {;}
int area(int w, int h) { return
w * h; }
};
• Le test passe toujours
TDD : exemple
28
⮚Test :
#include <assert.h>
#include "quad.h"
int main()
{
Quad q;
assert(6 == q.area(2, 3));
assert(10 == q.perimeter(2, 3));
return 0;
}
⮚Code :
class Quad {
public:
Quad () {;}
int area(int w, int h) { return
w * h; }
};
• Le test ne compile plus !
TDD : exemple
29
⮚Test :
#include <assert.h>
#include "quad.h"
int main()
{
Quad q;
assert(6 == q.area(2, 3));
assert(10 == q.perimeter(2, 3));
return 0;
}
⮚Code :
class Quad {
public:
Quad () {;}
int area(int w, int h) { return
w * h; }
int perimeter(int wd, int ht)
{ return 10; }
};
• Le test passe de nouveau !
TDD : exemple
30
⮚Test :
#include <assert.h>
#include "quad.h"
int main()
{
Quad q;
assert(6 == q.area(2, 3));
assert(10 == q.perimeter(2, 3));
return 0;
}
⮚Code :
class Quad {
public:
Quad () {;}
int area(int w, int h) { return
w * h; }
int perimeter(int wd, int ht)
{ return wd + wd + ht + ht; }
};
• Le test passe toujours !
TDD : exemple
31
⮚Test :
#include <assert.h>
#include "quad.h"
int main()
{
Quad q;
assert(6 == q.area(2, 3));
assert(10 == q.perimeter(2, 3));
return 0;
}
⮚Code :
class Quad {
public:
Quad (int wd, int ht) :
m_wd(wd),
m_ht(ht)
{;}
int area() { return m_wd * m_ht;
}
int perimeter()
{ return m_wd + m_wd + m_ht +
m_ht; }
private:
int m_wd;
int m_ht;
};
• Le code est refactorisé, mais le test ne compile plus !
• Sachant que le test ne passerait plus, il aurait pu être
modifié en premier
TDD : exemple
32
⮚Test :
#include <assert.h>
#include "quad.h"
int main()
{
Quad q(2, 3);
assert(6 == q.area());
assert(10 == q.perimeter());
return 0;
}
⮚Code :
class Quad {
public:
Quad (int wd, int ht) :
m_wd(wd),
m_ht(ht)
{;}
int area() { return m_wd * m_ht;
}
int perimeter()
{ return m_wd + m_wd + m_ht +
m_ht; }
private:
int m_wd;
int m_ht;
};
• Le test compile de nouveau et passe
❑ Cet exemple est loin d’être parfait et reste incomplet…
o En effet, la classe Quad accepte des valeurs négatives
o Faut-il ajouter des tests avec valeurs négatives ?
o Dans ce cas, elles doivent être testées dans le constructeur
o Faut-il modifier la classe avec des entiers non signés ?
❑ Si les tests réussissent, cela ne signifie pas qu’il n’y a pas de bug !
❑ En règle générale, le développeur doit toujours tester les valeurs extrêmes passées en
argument, les pointeurs nuls, les débordements de variables…
❑ La relecture de code par des pairs devrait donc aussi s’attarder sur les tests
❑ Attention à la refactorisation qui peut induire que le code n’est plus couvert par les
tests à 100%
TDD : exemple
33
❑ Un framework de tests unitaires fournit :
o Un langage commun pour exprimer les cas de test (eg: google test)
o Un langage commun pour exprimer les résultats attendus
o Permet d’accéder aux features du langage du code testé
o Collecte les résultats de test, fournit un rapport de test
o Fournit un mécanisme pour faire tourner les tests
o Soit tous les tests
o Soit seulement certains tests
❑ Quatre phases pour chaque test :
1. Etablissement des pré-conditions du test (passant/nominal et générant des
erreurs)
2. Exercice du code testé
3. Vérification des résultats
4. Retour du système testé à son état initial
❑ http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks
Test frameworks
34
❑ Les tests unitaires doivent être confinés à un processus
❑ Il est déconseillé d’avoir des tests unitaires faisant appel à des systèmes externes
(réseau, base de données, hardware, …)
o Ne pas confondre tests unitaires et tests d’intégration
o Dépendances externes pouvant influer sur les tests
o Ralentit l’exécution des tests unitaires
❑ Lorsque du code testé unitairement dépend d’une ressource externe, une interface
doit représenter cette ressource
❑ L’implémentation de cette interface doit être faite de deux façons :
o Appels réels
o Appels simulés ou stubbé/mock (Eg: google moc)
❑ Le code testé par tests unitaires appellera l’implémentation simulée/stubé/mocké
Injection de dépendances
35
❑ Fakes :
o Fonctions ou objets qui ne font pas grand-chose, mais qui permettent à un test de
vérifier un comportement correct
o Retour d’une valeur prédéterminée
❑ Mocks :
o Fonctions ou objets qui sont plus évolués que des fakes
o Peuvent contenir eux-mêmes des assertions
o Peuvent simuler un comportement
❑ Un avantage indéniable des fakes et mocks est la possibilité de simuler des conditions
d’erreur, ce qui est parfois impossibles à réaliser avec l’implémentation réelle
❑ Il reste possible de faire tourner une sélection des tests unitaires contre
l’implémentation réelle (= tests d’intégration)
Fakes & mocks
36
❑ Le test unitaire de fonctions statiques ou de méthodes privées reste un débat non
tranché
❑ Le problème est de permettre aux tests unitaires d’appeler ces fonctions :
o Différenciation des interfaces par #ifdef ou autres équivalents
o N’aide pas à garder un code propre
o Ajout de fonctions que les tests appelleront
o Ce peut être automatiquement fait par le préprocesseur
o Par pointeurs sur fonctions
o Certains langages offrent par « réflexion » un moyen de test
Fonctions statiques & méthodes
privées
37
❑ Pratique de TDD de 2003 à 2009 en C et C++ (embedded software)
o Dernier projet : 45Ksloc, ~600 tests, ~45 secondes
❑ TDD est contre intuitif au premier abord
o Ecrire les tests en premier
❑ Maîtriser TDD prend du temps
o Découplage des interfaces
o Eviter les dépendances entre tests
❑ TDD allié à d’autres techniques permet d’atteindre un niveau de maturité
(mesurable) impossible à atteindre autrement
o Stratégie globale de codage et de test
o Tests d’intégration et fonctionnels automatisés
o Une régression doit devenir la priorité numéro 1
o Si défaut trouvé en aval, rajouter un test en amont
Expérience personnelle
38
❑ Qualité du code de test doit être au même niveau que le code testé
o Aucun warning autorisé (au minimum -Wall –Wextra)
o Facilite la maintenance du code de test
❑ Appliquer TDD à du code existant est difficile voire parfois impossible
❑ TDD ne peut pas sauver un projet si les spécifications ne sont pas correctes
Expérience personnelle
39
Test unitaire / intégration continue
Frameworks de tests unitaires
41
❑ Il existe une multitude de framework par langage :
o C : xTests, CUnit, Google/test, API Sanity autotest,
CU, …
o C++ : Google/test, CppUnit, CppTest, Tpunit++, …
o Java : Junit, jWalk, …
o PHP : PHPUnit, line, jMock
o Python : PyUnit / xPyUnit / TestOOB, Nose
o ObjectiveC : Iphone unit testing, ObjcUnit, GHUnit, OCUnit
o Ruby : RSPec, Test::Unit, minitest
o Shell : assert.sh, shUnit/shUnit2, ATF, filterunit
o XML : Xunit, WUnit
Pour plus d’infos :
http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks
Système d’intégration continue
42
❑ L'intégration continue est un ensemble de pratiques utilisées en génie logiciel. Elles consistent à
vérifier à chaque modification de code source que le résultat des modifications ne produit pas de
régression de l'application en cours de développement. Bien que le concept existait auparavant,
l'intégration continue se réfère généralement à la pratique de l'extreme programming.
❑ Il existe une multitude de logiciels d’intégration continue :
o Apache Continuum
o Bamboo
o Buildbot
o CruiseControl
o Jenkins/Hudson
o Gitlab
Pour plus d’information :
http://en.wikipedia.org/wiki/Comparison_of_continuous_integration_software
❑ Le fuzzing est une technique pour tester des logiciels. L'idée est d'injecter des données aléatoires
dans les entrées d'un programme. Si le programme échoue (par exemple en crashant ou en
générant une erreur), alors il y a des défauts à corriger. Exemples de point d'entrée d'un
programme :
o Fichiers ;
o Périphériques (clavier, souris, …) ;
o Variable d’environement
o Réseau
o Limitation de ressources (CPU, Mémoire, Accès I/O, … ) ;
o Etc …
Fuzzing
43
❑ Le grand avantage du fuzzing est que l'écriture de tests est extrêmement simple, ne demande aucune
connaissance du fonctionnement du système et permet de trouver des vulnérabilités facilement.
D'ailleurs, le fuzzing est également utilisé pour traquer des failles de sécurité ou dans la rétro-
ingénierie.
❑ La première trace du fuzzing est la publication datant du 12 décembre 1990 : « An Empirical Study of
the Reliability of UNIX Utilities » [1] écrite par Barton P. Miller, Lars Fredriksen, et Bryan So. Le résumé
indique que durant les essais ils ont été capables de crasher 25 à 33% des programmes utilitaires de
n'importe quelle version d'UNIX ». Le rapport présente les outils de test mais également l'origine des
erreurs.
❑ Le fuzzing est tellement simple à utiliser et efficace pour trouver des vulnérabilités que le chercheur
en sécurité informatique Charlie Miller a refusé de dévoiler les vulnérabilités zero day trouvées dans le
code de logiciels célèbres (contrairement au règlement du concours de sécurité informatique
Pwn2own), afin de protester contre les éditeurs qui n'utilisent pas assez cette technique simple selon
lui.
❑ Inversement au fuzzing qui est une méthode de test par boîte noire, la méthode de test par boîte
blanche analyse un système dont on connaît exactement le fonctionnement.
fuzzing
44
Retours d’expériences :
[ google test, google mock,
jenkins, c++ ]
❑ 🡪 Google/test : framework multiplateforme permettant l’écriture de tests en C/C++.
Basé sur l’architecture xUnit il supporte la découverte de tests en automatique et offre
une multitude de macro.
o Avantage(s):
o Facile à utiliser via un ensemble de macros
o Nombre de fonctionnalités (jouer un test x fois, random, … )
o Compatible xUnit
o Inconvénient(s):
o Mauvais support autotools
❑ 🡪 Google/mock :
o Avantage(s):
o Permet de tester des composants complexes
o Inconvénient(s):
o Peut être complexe à implémenter (doit être inclus dans les plannings)
o Risque de dérive par rapport au comportement réel
Google test / mock
46
TDD & C/C++/google test
Développement d’un composant suivant une démarche TDD
47
foo.h/hpp
API
(H/HPP)
Framework
Google/test
Composant compilé par
gcc/g++ :
- binaire sans le main()
- Librairie
statique/dynamique
Test unitaire
gtest_foo.cpp
testant l’API de foo.h
Test unitaire
Librairie
gtest.so
LINK par LD
Exigences
API
API
gtest.
h
libgest
s.so
API
CODE
foo.o gtest_foo.o
Runtime: ./gtest_foo
Résultat des tests au format
48
TDD & C/C++/google test
Développement d’un composant suivant une démarche TDD
SUT
MOCK
1
MOCK 2
(STUB)
Composant en
développement
(C/C++)
API
(H/HPP)
Test unitaire
LINK par LD
framework
Google/test
Programme
de tests basé
sur l’API
Résultat des tests au format
Junit/XML
pilotag
e
pilotag
e
Composant
Réel
(Ex: bdd)
TDD / C++ / JENKINS
49
Jenkins
Repository
GIT,
Clearcase,
Subversion,
…
Développeur
d’un composant
trigger
Build du composant: make
Configuration du composant:
./configure –prefix=/usr
Installation dans le stagingdir:
make DESTDIR=<stagingdir> install
Installation dans le rootfs final:
make DESTDIR=<rootfsdir> install
Lancement des tests unitaires:
make check
Mesure de couverture de code:
gcov/lcov
Génération de la doc au format
doxygen: make html
Retours d’expériences :
[ JSEE, JSF, Hibernate, Spring ]
❑ Contexte : Création d’une application Web de gestion
❑ Technologies Projet : J2EE, JSF, Hibernate, Spring
❑ Mode de contractualisation : Forfait Agile/SCRUM
❑ Sprints (itérations) de 4 semaines
❑ Mise en œuvre de pratiques d’eXtreme Programming :
o Test Driven Development : développement orienté par les tests
o Revue de pair
o Intégration Continue
❑ Solution technique
o Tests unitaires sur les couches métiers : JUnit
o Serveur d’intégration continue : Hudson
o Plugins :
o JUnit : non régression
o Duplicate Code : code dupliqué et factorisation possible
o CheckStyle : respect des règles de développement
o PMD : qualité du code
o Cobertura : couverture du code par les tests unitaires
o Java NCSS : commentaires & documentation
REX Viaccess : contexte
51
REX Viaccess : Architecture de l’usine
développement
52
❑ Itérations courtes : JUnit permet de se protéger contre la régression et évite de
retester exhaustivement l’application à chaque itération
❑ Avantages :
o passage automatique :
o à chaque modification dans SVN
o Régulièrement (toutes les 2 heures ou build de nuit)
o notification des résultats part mail
❑ Inconvénients : se limite aux tests unitaires
❑ développés
REX Viaccess : JUnit
53
❑ Duplicate Code : code dupliqué et factorisation possible
❑ Avantages : reconnait les des bouts de code copiés/collés
mais également des structures de données approchantes
=> conception objet à améliorer
❑ Inconvénients :
❑ ne prend pas en
❑ compte le métier
REX Viaccess : Duplicate Code
54
❑ Respect des règles de développement
❑ Avantages :
o paramétrable suivant les règles de
développement du client
o Apporte une explication détaillée
sur comment corrigé le problème
❑ Inconvénients : aucun
REX Viaccess : CheckStyle
55
❑ PMD : qualité du code
❑ Avantages :
❑ Inconvénients :
REX Viaccess : PMD
56
❑ Cobertura permet de vérifier la couverture du code par
les tests unitaires
❑ Avantages :
❑ Inconvénients :
REX Viaccess : Cobertura
57
❑ Java NCSS : mensure du taux de commentaires et de documentation
❑ Avantage : donne une indication de l’état du projet
❑ Inconvénient : résultats pas exploitable pour action
REX Viaccess : Java NCSS
58
DEVSECOPS & CI/CD
CI : Continuous Integration
CD : Continuous Deployment
DEVSECOPS
60
DEVSECOPS
61
IAC : Infrastructure As Code
IAST : Interactive Application Security Testing
RASP : Runtime Application Self-Protection
SCA : Software Composition Analysis
SAST : Static Application Security Testing
DAST : Dynamic Application Security Testing
WAF : Web Application Firewall
WAAS : Web Application Acceleration Service
DEVSECOPS
62
DEVSECOPS
63
DEVSECOPS
64
DEVSECOPS
65
ANY QUESTIONS ?
This work is licensed under a Creative Commons
Attribution-ShareAlike 3.0 Unported License.
It makes use of the works of Mateus Machado Luna.

Présentation des test driven development aka tdd

  • 1.
  • 2.
    ❑ Introduction ❑ Méthodestraditionnelles et tests ❑ Impacts et coût des défauts ❑ Test Driven Development ❑ Définition ❑ Méthodologie ❑ Avantages, inconvénients ❑ Injection de dépendances, fakes et mocks ❑ Exemple ❑ Expérience personnelle Introduction 2
  • 3.
  • 4.
    ❑ Le codelogiciel est fragile ❑ Quasiment n’importe quel changement peut avoir des conséquences inattendues ❑ Le but de cette présentation est de montrer une méthode de développement qui permet d'améliorer la qualité logiciel, et de réduire les coûts de développement ❑ Grâce à cette méthode, nous pourrons à tout moment nous assurer de la maturité du logiciel, et être immédiatement averti de toute déviation, régression ou défaut, et ce dès leur introduction dans le code. Programmation Pilotée par les Tests = Test Driven Development Introduction 4
  • 5.
    Méthodes traditionnelles :waterfall 5 User requirements Functional specification s Global technical design Detailed technical design Programming Testing CODE DRIVEN DEVELOPMENT
  • 6.
    Méthodes traditionnelles :cycle en V 6 User requirement s Functional specification s Global technical design Detailed technical design Programming Component tests Integration tests System tests Acceptance tests
  • 7.
    ❑ Lorsque lestests ne sont pas automatisés, éventuellement seuls les tests que l’on pense être nécessaires seront utilisés ❑ Parfois seulement des tests fonctionnels sont utilisés (surtout en waterfall), rendant souvent impossible le test des gestions d’erreurs ❑ Les tests unitaires (si existants) sont ajoutés après la phase de codage ❑ Couverture de code non complète ❑ Tout le code n’est pas testable (couplage fort entre interfaces) ❑ Tendre vers 100% de couverture demande un effort exponentiel ❑ On ne connaît pas la maturité du code avant les phases de test (et les résultats peuvent être trompeurs) Méthodes traditionnelles & tests 7
  • 8.
    Méthodes traditionnelles &tests 8 ❑ La détection des défauts intervient bien après la phase de codage ❑ Tous les défauts ne peuvent pas être découverts ❑ Un bug simple peut n’être découvert que très tard ❑ Plus un bug est trouvé tard, plus il est coûteux à fixer ❑ La qualité d’un logiciel ne se mesure pas seulement dans son comportement ni dans ses performances ❑ Le code doit être maintenable, donc simple à comprendre ❑ Conséquences : ❑ Aucune ou peu de confiance dans la maturité du code ❑ Le projet prend du retard ❑ Les coûts ne sont pas maîtrisés
  • 9.
    Méthodes traditionnelles :coût des défauts 9 Source : Software Engineering Economics, B.W. Boehm, 1981
  • 10.
    Exemple de bugcouteux 10 ❑ Ariane 5 – Juin 1996 o Un bug du logiciel de la fusée provoqua son autodestruction : o Récupération du soft Ariane 4 : accélération codée sur 8 bit o Sur Ariane 5 (accélération plus grande) => dépassement de capacité (9 bits auraient été nécessaires) o Les pertes sont estimées à un total de 370 millions de dollars. o http://fr.wikipedia.org/wiki/Vol_501_d%27Ariane_5 ❑ Therac-25 o Machine de radiothérapie, évolution des modèles précédents o Entre 1985 et 1987, des patients reçurent des doses massives de radiation, au moins cinq patients décédèrent. o Plusieurs problèmes de gestion du projet informatique furent découverts après enquête, dont des tests logiciels incomplets. o http://fr.wikipedia.org/wiki/Therac-25
  • 11.
    Tests unitaires :pas suffisant ! 11 Code testé : int checksum(void *p, int len) { int sum = 0; unsigned char* pp = (unsigned char*)p; int i; for (i = 0; i <= len; i++) { sum += *pp++; } return sum; } ❑ Test unitaire : char *myString = "foo"; assert(324 == checksum(myString, strlen(myString))); ❑ Couverture incomplète : bug potentiel non détecté ! Le problème avec cette fonction checksum est dans la boucle for. La condition i <= len doit être corrigée pour i < len, car sinon, la boucle parcourra un octet de plus que la longueur réelle de la chaîne, ce qui entraînera un dépassement de mémoire tampon et un comportement indéfini. De plus, vous devriez utiliser un type de donnée plus grand pour stocker la somme, comme unsigned int, pour éviter un débordement de la somme en cas de longues chaînes.
  • 12.
    ❑ Code testé: void checkRange(int i, int j) { if (i >= 3) throw std::exception("out of range"); if (j >= 3) throw std::exception("out of range"); } ❑ Test unitaire : 100% de couverture EXPECT_THROW(checkRange(0, 3)) EXPECT_THROW(checkRange(3, 0)) ❑ Mais supposons qu’un nombre négatif ne soit pas admis : checkRange(-1, 2); Tests unitaires : pas suffisant ! 12 Le problème principal avec cette fonction est qu'elle utilise std::exception de manière incorrecte. std::exception est une classe de base pour toutes les exceptions standard C++, mais elle n'a pas de constructeur qui prend une chaîne de caractères comme argument. Pour créer une exception personnalisée avec un message, vous devez définir votre propre classe d'exception dérivée de std::exception et fournir un constructeur prenant une chaîne de caractères comme argument. EXPECT_THROW(checkRange(0, 3), std::out_of_range); EXPECT_THROW(checkRange(3, 0), std::out_of_range); try { checkRange(-1, 2); } catch (const std::out_of_range& e) { // Gérer l'exception ici } Cette correction permet à la fonction checkRange de lancer une exception std::out_of_range avec un message spécifique lorsque les valeurs i ou j sont en dehors de la plage spécifiée.
  • 13.
    ❑ TDD estune méthode de développement incrémental ❑ Le principe : o En testant en premier, je conçois le code ❑ La méthode : o Aucun code n’est implémenté avant d’avoir écrit un test unitaire qui échoue o Ensuite, le code est implémenté, le test unitaire réussi ❑ Origine : o eXtreme Programming (XP) o 1999 Kent Beck, Martin Fowler et autres… ❑ Souvent utilisé dans un cycle Agile, mais ce n’est pas obligatoire ! ❑ Très orienté DEVSECOPS avec des cycles CI/CD ! TDD 13
  • 14.
  • 15.
    ❑ TDD inversela méthode classique de codage en premier et debug plus tard ❑ TDD implique que le développeur d’un module se concentre donc dès le début sur : o Son interface : comment vais-je l’utiliser ? o Son comportement : que fait-il ? o Sa réutilisation : clients multiples du code et des tests o Ses dépendances : il doit être testé de façon isolée o Sa cohésion : un module testable a une raison d’être ❑ Les détails d’implémentation sont secondaires ❑ Ceci encourage le découplage des interfaces o Code plus modulaire o Un système découplé est plus évolutif ❑ Chaque ajout de code aura un test ou des tests correspondant Commencer par écrire des tests ? 15 Tests unitaires pour tester : - ses classes - ses API privées - ses API publiques
  • 16.
    ❑ L’automatisation destests est un élément clé de TDD o Continuous Integration (aka CI) ❑ Les tests sont simples ❑ A chaque étape du développement, de nouveaux tests sont ajoutés, suivi de l’implémentation ❑ A chaque changement introduit dans du code existant, les tests sont exécutés o Test du nouveau code o Test du code existant ❑ Toute régression est ainsi immédiatement trouvée et est facile à corriger Automatisation 16
  • 17.
    Coûts des défauts 17 Bugintroduit Bug découvert Cause trouvée Correction Bug introduit Bug découvert Cause trouvée Correction ❑ Traditionnelleme nt : ❑ Avec TDD : Parallélisation, réduction des temps d’action !
  • 18.
    ❑ Meilleure couverturede test (but : 100%) ❑ Moins de défauts, moins d’effets de bord, moins de temps passé à debugger ❑ Le code est conçu de façon à être plus facile à tester ❑ Code plus modulaire ❑ Design plus propre et plus facile à comprendre ❑ La refactorisation devient plus facile ❑ Les tests constituent une documentation bas-niveau o Pour chaque feature, il y a au moins un exemple d’utilisation o Toujours à jour ! TDD : avantages 18
  • 19.
    ❑ TDD negarantie pas une bonne architecture ou design ❑ TDD est plus difficile à utiliser dans les situations où des tests fonctionnels sont requis pour déterminer le succès ou l'échec o Interfaces homme-machine o Base de données o Réseaux ❑ Le support du management est essentiel o Sans l’entière organisation convaincue que TDD va améliorer le produit, le temps passé à écrire les tests est souvent vu comme perdu ❑ Les tests sont typiquement écrits par le développeur du code testé ❑ TDD ne remplace pas les autres activités de test (intégration, validation, conformité, etc) TDD : vulnérabilités 19
  • 20.
    ❑ Bob Martindécrit TDD avec trois règles simples : o Do not write production code unless it is to make a failing unit test pass ; o Do not write more of a unit test than is sufficient to fail, and build failures are failures ; o Do not write more production code than is sufficient to pass the one failing unit test. http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd TDD : les trois lois 20
  • 21.
  • 22.
    ❑ Les testsmontrent que le comportement est correct : le code fonctionne ❑ Mais du code doit être propre et bien structuré o Plus facile à comprendre o Plus facile à faire évoluer o Plus facile à maintenir ❑ C’est le but de la dernière étape du microcycle ❑ La refactorisation est l’activité de changer la structure d’un code sans en changer son comportement ❑ Souvent appelé « Red-Green-Refactor » TDD : refactorisation 22
  • 23.
  • 24.
    Exemple avec uneclasse en C++
  • 25.
    TDD : exemple 25 ⮚Test: #include <assert.h> #include "quad.h" int main() { Quad q; assert(6 == q.area(2, 3)); return 0; } ⮚Code : • Le test ne compile pas car le code est inexistant !
  • 26.
    TDD : exemple 26 ⮚Test: #include <assert.h> #include "quad.h" int main() { Quad q; assert(6 == q.area(2, 3)); return 0; } ⮚Code : class Quad { public: Quad () {;} int area(int w, int h) { return 6; } }; → Cette fonction a pour but de calculer l’aire d’un quadilatère. • Le test compile et réussi !
  • 27.
    TDD : exemple 27 ⮚Test: #include <assert.h> #include "quad.h" int main() { Quad q; assert(6 == q.area(2, 3)); return 0; } ⮚Code : class Quad { public: Quad () {;} int area(int w, int h) { return w * h; } }; • Le test passe toujours
  • 28.
    TDD : exemple 28 ⮚Test: #include <assert.h> #include "quad.h" int main() { Quad q; assert(6 == q.area(2, 3)); assert(10 == q.perimeter(2, 3)); return 0; } ⮚Code : class Quad { public: Quad () {;} int area(int w, int h) { return w * h; } }; • Le test ne compile plus !
  • 29.
    TDD : exemple 29 ⮚Test: #include <assert.h> #include "quad.h" int main() { Quad q; assert(6 == q.area(2, 3)); assert(10 == q.perimeter(2, 3)); return 0; } ⮚Code : class Quad { public: Quad () {;} int area(int w, int h) { return w * h; } int perimeter(int wd, int ht) { return 10; } }; • Le test passe de nouveau !
  • 30.
    TDD : exemple 30 ⮚Test: #include <assert.h> #include "quad.h" int main() { Quad q; assert(6 == q.area(2, 3)); assert(10 == q.perimeter(2, 3)); return 0; } ⮚Code : class Quad { public: Quad () {;} int area(int w, int h) { return w * h; } int perimeter(int wd, int ht) { return wd + wd + ht + ht; } }; • Le test passe toujours !
  • 31.
    TDD : exemple 31 ⮚Test: #include <assert.h> #include "quad.h" int main() { Quad q; assert(6 == q.area(2, 3)); assert(10 == q.perimeter(2, 3)); return 0; } ⮚Code : class Quad { public: Quad (int wd, int ht) : m_wd(wd), m_ht(ht) {;} int area() { return m_wd * m_ht; } int perimeter() { return m_wd + m_wd + m_ht + m_ht; } private: int m_wd; int m_ht; }; • Le code est refactorisé, mais le test ne compile plus ! • Sachant que le test ne passerait plus, il aurait pu être modifié en premier
  • 32.
    TDD : exemple 32 ⮚Test: #include <assert.h> #include "quad.h" int main() { Quad q(2, 3); assert(6 == q.area()); assert(10 == q.perimeter()); return 0; } ⮚Code : class Quad { public: Quad (int wd, int ht) : m_wd(wd), m_ht(ht) {;} int area() { return m_wd * m_ht; } int perimeter() { return m_wd + m_wd + m_ht + m_ht; } private: int m_wd; int m_ht; }; • Le test compile de nouveau et passe
  • 33.
    ❑ Cet exempleest loin d’être parfait et reste incomplet… o En effet, la classe Quad accepte des valeurs négatives o Faut-il ajouter des tests avec valeurs négatives ? o Dans ce cas, elles doivent être testées dans le constructeur o Faut-il modifier la classe avec des entiers non signés ? ❑ Si les tests réussissent, cela ne signifie pas qu’il n’y a pas de bug ! ❑ En règle générale, le développeur doit toujours tester les valeurs extrêmes passées en argument, les pointeurs nuls, les débordements de variables… ❑ La relecture de code par des pairs devrait donc aussi s’attarder sur les tests ❑ Attention à la refactorisation qui peut induire que le code n’est plus couvert par les tests à 100% TDD : exemple 33
  • 34.
    ❑ Un frameworkde tests unitaires fournit : o Un langage commun pour exprimer les cas de test (eg: google test) o Un langage commun pour exprimer les résultats attendus o Permet d’accéder aux features du langage du code testé o Collecte les résultats de test, fournit un rapport de test o Fournit un mécanisme pour faire tourner les tests o Soit tous les tests o Soit seulement certains tests ❑ Quatre phases pour chaque test : 1. Etablissement des pré-conditions du test (passant/nominal et générant des erreurs) 2. Exercice du code testé 3. Vérification des résultats 4. Retour du système testé à son état initial ❑ http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks Test frameworks 34
  • 35.
    ❑ Les testsunitaires doivent être confinés à un processus ❑ Il est déconseillé d’avoir des tests unitaires faisant appel à des systèmes externes (réseau, base de données, hardware, …) o Ne pas confondre tests unitaires et tests d’intégration o Dépendances externes pouvant influer sur les tests o Ralentit l’exécution des tests unitaires ❑ Lorsque du code testé unitairement dépend d’une ressource externe, une interface doit représenter cette ressource ❑ L’implémentation de cette interface doit être faite de deux façons : o Appels réels o Appels simulés ou stubbé/mock (Eg: google moc) ❑ Le code testé par tests unitaires appellera l’implémentation simulée/stubé/mocké Injection de dépendances 35
  • 36.
    ❑ Fakes : oFonctions ou objets qui ne font pas grand-chose, mais qui permettent à un test de vérifier un comportement correct o Retour d’une valeur prédéterminée ❑ Mocks : o Fonctions ou objets qui sont plus évolués que des fakes o Peuvent contenir eux-mêmes des assertions o Peuvent simuler un comportement ❑ Un avantage indéniable des fakes et mocks est la possibilité de simuler des conditions d’erreur, ce qui est parfois impossibles à réaliser avec l’implémentation réelle ❑ Il reste possible de faire tourner une sélection des tests unitaires contre l’implémentation réelle (= tests d’intégration) Fakes & mocks 36
  • 37.
    ❑ Le testunitaire de fonctions statiques ou de méthodes privées reste un débat non tranché ❑ Le problème est de permettre aux tests unitaires d’appeler ces fonctions : o Différenciation des interfaces par #ifdef ou autres équivalents o N’aide pas à garder un code propre o Ajout de fonctions que les tests appelleront o Ce peut être automatiquement fait par le préprocesseur o Par pointeurs sur fonctions o Certains langages offrent par « réflexion » un moyen de test Fonctions statiques & méthodes privées 37
  • 38.
    ❑ Pratique deTDD de 2003 à 2009 en C et C++ (embedded software) o Dernier projet : 45Ksloc, ~600 tests, ~45 secondes ❑ TDD est contre intuitif au premier abord o Ecrire les tests en premier ❑ Maîtriser TDD prend du temps o Découplage des interfaces o Eviter les dépendances entre tests ❑ TDD allié à d’autres techniques permet d’atteindre un niveau de maturité (mesurable) impossible à atteindre autrement o Stratégie globale de codage et de test o Tests d’intégration et fonctionnels automatisés o Une régression doit devenir la priorité numéro 1 o Si défaut trouvé en aval, rajouter un test en amont Expérience personnelle 38
  • 39.
    ❑ Qualité ducode de test doit être au même niveau que le code testé o Aucun warning autorisé (au minimum -Wall –Wextra) o Facilite la maintenance du code de test ❑ Appliquer TDD à du code existant est difficile voire parfois impossible ❑ TDD ne peut pas sauver un projet si les spécifications ne sont pas correctes Expérience personnelle 39
  • 40.
    Test unitaire /intégration continue
  • 41.
    Frameworks de testsunitaires 41 ❑ Il existe une multitude de framework par langage : o C : xTests, CUnit, Google/test, API Sanity autotest, CU, … o C++ : Google/test, CppUnit, CppTest, Tpunit++, … o Java : Junit, jWalk, … o PHP : PHPUnit, line, jMock o Python : PyUnit / xPyUnit / TestOOB, Nose o ObjectiveC : Iphone unit testing, ObjcUnit, GHUnit, OCUnit o Ruby : RSPec, Test::Unit, minitest o Shell : assert.sh, shUnit/shUnit2, ATF, filterunit o XML : Xunit, WUnit Pour plus d’infos : http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks
  • 42.
    Système d’intégration continue 42 ❑L'intégration continue est un ensemble de pratiques utilisées en génie logiciel. Elles consistent à vérifier à chaque modification de code source que le résultat des modifications ne produit pas de régression de l'application en cours de développement. Bien que le concept existait auparavant, l'intégration continue se réfère généralement à la pratique de l'extreme programming. ❑ Il existe une multitude de logiciels d’intégration continue : o Apache Continuum o Bamboo o Buildbot o CruiseControl o Jenkins/Hudson o Gitlab Pour plus d’information : http://en.wikipedia.org/wiki/Comparison_of_continuous_integration_software
  • 43.
    ❑ Le fuzzingest une technique pour tester des logiciels. L'idée est d'injecter des données aléatoires dans les entrées d'un programme. Si le programme échoue (par exemple en crashant ou en générant une erreur), alors il y a des défauts à corriger. Exemples de point d'entrée d'un programme : o Fichiers ; o Périphériques (clavier, souris, …) ; o Variable d’environement o Réseau o Limitation de ressources (CPU, Mémoire, Accès I/O, … ) ; o Etc … Fuzzing 43
  • 44.
    ❑ Le grandavantage du fuzzing est que l'écriture de tests est extrêmement simple, ne demande aucune connaissance du fonctionnement du système et permet de trouver des vulnérabilités facilement. D'ailleurs, le fuzzing est également utilisé pour traquer des failles de sécurité ou dans la rétro- ingénierie. ❑ La première trace du fuzzing est la publication datant du 12 décembre 1990 : « An Empirical Study of the Reliability of UNIX Utilities » [1] écrite par Barton P. Miller, Lars Fredriksen, et Bryan So. Le résumé indique que durant les essais ils ont été capables de crasher 25 à 33% des programmes utilitaires de n'importe quelle version d'UNIX ». Le rapport présente les outils de test mais également l'origine des erreurs. ❑ Le fuzzing est tellement simple à utiliser et efficace pour trouver des vulnérabilités que le chercheur en sécurité informatique Charlie Miller a refusé de dévoiler les vulnérabilités zero day trouvées dans le code de logiciels célèbres (contrairement au règlement du concours de sécurité informatique Pwn2own), afin de protester contre les éditeurs qui n'utilisent pas assez cette technique simple selon lui. ❑ Inversement au fuzzing qui est une méthode de test par boîte noire, la méthode de test par boîte blanche analyse un système dont on connaît exactement le fonctionnement. fuzzing 44
  • 45.
    Retours d’expériences : [google test, google mock, jenkins, c++ ]
  • 46.
    ❑ 🡪 Google/test: framework multiplateforme permettant l’écriture de tests en C/C++. Basé sur l’architecture xUnit il supporte la découverte de tests en automatique et offre une multitude de macro. o Avantage(s): o Facile à utiliser via un ensemble de macros o Nombre de fonctionnalités (jouer un test x fois, random, … ) o Compatible xUnit o Inconvénient(s): o Mauvais support autotools ❑ 🡪 Google/mock : o Avantage(s): o Permet de tester des composants complexes o Inconvénient(s): o Peut être complexe à implémenter (doit être inclus dans les plannings) o Risque de dérive par rapport au comportement réel Google test / mock 46
  • 47.
    TDD & C/C++/googletest Développement d’un composant suivant une démarche TDD 47 foo.h/hpp API (H/HPP) Framework Google/test Composant compilé par gcc/g++ : - binaire sans le main() - Librairie statique/dynamique Test unitaire gtest_foo.cpp testant l’API de foo.h Test unitaire Librairie gtest.so LINK par LD Exigences API API gtest. h libgest s.so API CODE foo.o gtest_foo.o Runtime: ./gtest_foo Résultat des tests au format
  • 48.
    48 TDD & C/C++/googletest Développement d’un composant suivant une démarche TDD SUT MOCK 1 MOCK 2 (STUB) Composant en développement (C/C++) API (H/HPP) Test unitaire LINK par LD framework Google/test Programme de tests basé sur l’API Résultat des tests au format Junit/XML pilotag e pilotag e Composant Réel (Ex: bdd)
  • 49.
    TDD / C++/ JENKINS 49 Jenkins Repository GIT, Clearcase, Subversion, … Développeur d’un composant trigger Build du composant: make Configuration du composant: ./configure –prefix=/usr Installation dans le stagingdir: make DESTDIR=<stagingdir> install Installation dans le rootfs final: make DESTDIR=<rootfsdir> install Lancement des tests unitaires: make check Mesure de couverture de code: gcov/lcov Génération de la doc au format doxygen: make html
  • 50.
    Retours d’expériences : [JSEE, JSF, Hibernate, Spring ]
  • 51.
    ❑ Contexte :Création d’une application Web de gestion ❑ Technologies Projet : J2EE, JSF, Hibernate, Spring ❑ Mode de contractualisation : Forfait Agile/SCRUM ❑ Sprints (itérations) de 4 semaines ❑ Mise en œuvre de pratiques d’eXtreme Programming : o Test Driven Development : développement orienté par les tests o Revue de pair o Intégration Continue ❑ Solution technique o Tests unitaires sur les couches métiers : JUnit o Serveur d’intégration continue : Hudson o Plugins : o JUnit : non régression o Duplicate Code : code dupliqué et factorisation possible o CheckStyle : respect des règles de développement o PMD : qualité du code o Cobertura : couverture du code par les tests unitaires o Java NCSS : commentaires & documentation REX Viaccess : contexte 51
  • 52.
    REX Viaccess :Architecture de l’usine développement 52
  • 53.
    ❑ Itérations courtes: JUnit permet de se protéger contre la régression et évite de retester exhaustivement l’application à chaque itération ❑ Avantages : o passage automatique : o à chaque modification dans SVN o Régulièrement (toutes les 2 heures ou build de nuit) o notification des résultats part mail ❑ Inconvénients : se limite aux tests unitaires ❑ développés REX Viaccess : JUnit 53
  • 54.
    ❑ Duplicate Code: code dupliqué et factorisation possible ❑ Avantages : reconnait les des bouts de code copiés/collés mais également des structures de données approchantes => conception objet à améliorer ❑ Inconvénients : ❑ ne prend pas en ❑ compte le métier REX Viaccess : Duplicate Code 54
  • 55.
    ❑ Respect desrègles de développement ❑ Avantages : o paramétrable suivant les règles de développement du client o Apporte une explication détaillée sur comment corrigé le problème ❑ Inconvénients : aucun REX Viaccess : CheckStyle 55
  • 56.
    ❑ PMD :qualité du code ❑ Avantages : ❑ Inconvénients : REX Viaccess : PMD 56
  • 57.
    ❑ Cobertura permetde vérifier la couverture du code par les tests unitaires ❑ Avantages : ❑ Inconvénients : REX Viaccess : Cobertura 57
  • 58.
    ❑ Java NCSS: mensure du taux de commentaires et de documentation ❑ Avantage : donne une indication de l’état du projet ❑ Inconvénient : résultats pas exploitable pour action REX Viaccess : Java NCSS 58
  • 59.
    DEVSECOPS & CI/CD CI: Continuous Integration CD : Continuous Deployment
  • 60.
  • 61.
    DEVSECOPS 61 IAC : InfrastructureAs Code IAST : Interactive Application Security Testing RASP : Runtime Application Self-Protection SCA : Software Composition Analysis SAST : Static Application Security Testing DAST : Dynamic Application Security Testing WAF : Web Application Firewall WAAS : Web Application Acceleration Service
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
    This work islicensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. It makes use of the works of Mateus Machado Luna.