Tests unitaire, refactoring, test-driven development, TDD, clean code, design pattern, bonnes pratiques en équipe.
Un tour rapide sur où placer les tests unitaires et le développement dirigé par les tests, dans les bonnes pratiques de développement logiciel.
2. I am Hadrien Blanc
Responsable pédagogique Epitech
@hadrienblanc
blanc.hadrien@gmail.com
www.linkedin.com/in/hadrienblanc
HELLO!
3. Ariane 5
1/2
Ariane 5 cas "funny":
▸Explosion après 40
secondes
▸10 ans et 7 milliards de $
▸Conversion d'un float 64 bit
vers un entier non signé 16
bit
4. Ariane 5
2/2
Principale explication:
"no test was performed to
verify that the Inertial Reference
System would behave correctly
when being subjected to the
count-down and flight time
sequence and the trajectory of
Ariane 5."
▸ ARIANE 5 Flight 501 Failure Report by the Inquiry Board
The Chairman of the Board : Prof. J. L. LIONS
5. “Software must be soft: it
has to be easy to change
because it will change
despite our misguided
efforts otherwise.”
The pragmatic Programmers
6. Cependant, le code est
difficile à modifier lorsqu'il
est :
1. Pas lisible
2. Dupliqué
3. Compliqué
7. "Any fool can write code
that a computer can
understand"
Martin Fowler
9. Lisibilité du
code
Pistes sur la lisibilité du code:
▸ Style d’Indentation cohérent
▸ Éviter les commentaires évidents
▸ Nommage des variables et fonctions
cohérents
▸ DRY - Don’t Repeat Yourself
▸ Niveaux multiples de parenthèses
▸ Taille limite de la ligne
▸ Organisation des dossiers
▸ KISS
▸ Utilisation de Design pattern
10. Style
d'indentation
cohérent 1/2
while (x == y) {
something();
somethingelse();
}
K&R and variants:
1TBS, Stroustrup, Linux kernel, BSD KNF
while (x == y)
{
something();
somethingelse();
}
Allman style (Bsd)
while (x == y)
{
something();
somethingelse();
}
Gnu
while (x == y)
{
something();
somethingelse();
}
Whitesmiths
12. Éviter les
commentaires
évidents 1/2
//Extraire les données de l’ancien système
functionD1();
//Transformer les données
functionD2();
//Charger les données dans le nouveau système
functionD3();
VS
Extract();
Transform();
Load();
"Si le code est tellement compliqué que cela doit
être expliqué, il est presque toujours préférable
d’améliorer le code que d’ajouter des
commentaires"
▸ Steve Mcconnell
14. Nommages
de variable
cohérent 1/2
Les noms des constantes symboliques et des
macros instructions doivent être écrits en
majuscule.
#define LONGUEUR_NOM_FICHIER 15
#define STR(s) #s
#define XSTR(s) STR(s)
16. DRY Don't
Repeat
Yourself 1/2
"Every piece of knowledge must
have a single, unambiguous,
authoritative representation
within a system."
Livre The Pragmatic Programmer
VS
WET
"Write Everything Twice"
"We Enjoy Typing"
"Waste Everyone's Time"
17. DRY 2/2
Echo "Hello Hadrien, how are you doing ?";
Echo "Hello Sergei, how are you doing ?";
Echo "Hello you, how are you doing ?";
VS
function greetings($str) {
echo "Hello $str, how are you doing ? "
}
greetings("Hadrien");
greetings("Sergei");
greetings("you");
19. Organisation
des dossiers
app/
The application configuration, templates and
translations.
bin/
Executable files (e.g. bin/console).
src/
The project's PHP code.
tests/
Automatic tests (e.g. Unit tests).
var/
Generated files (cache, logs, etc.).
vendor/
The third-party dependencies.
web/
The web root directory.
20. KISS
KISS - Keep It Simple
1.D'abord un code fonctionnel
2.Puis optimisation
3.En gardant un code
fonctionnel
21. Design
Pattern
▸ Factory Method
Création d'objet sans spécifier la
classe exacte
$factory = new SedanFactory();
$car = $factory->makeCar();
print $car->getType();
▸ Singleton
Utilisation d'un objet dans le code
▸ Facade
Simplifier une interface
22. S'améliorer
Comment améliorer la lisibilité,
simplicité, éviter la duplication du code
?
Pistes:
▸ Parcourir du code open-source
(contribuer ?)
▸ Lire des blogs
▸ Lire des livres
▸ ...
26. WHY ?
Unit test : pourquoi ?
Le métier d'ingénieur logiciel évolue :
▸ Désign
▸ Développement
▸ Test
▸ Déploiement
▸ Résolution de bugs
Concepteur/Architecte + Développeur +
Ingénieur qualité + administrateur système +
ingénieur production
30. "Le test-driven development (TDD) ou
en français développement piloté par
les tests est une technique de
développement de logiciel qui
préconise d'écrire les tests unitaires
avant d'écrire le code source d'un
logiciel."
-- Wikipedia
31. Ne pas
confondre
1. Écrire du code
2. Ajout des tests
3. Modification du code pour passer
VS
1. Écrire des tests
2. Écrire du code qui passe les tests
(Test Driven Development)
32. TDD En
détail
Le cycle TDD en détail :
1. Écrire un premier test
2. Vérifier qu'il échoue (car le code
n'existe pas encore)
3. Écrire juste le code suffisant pour
passer le test
4. Vérifier que le test passe
5. Puis réusiner le code, refactoring.
34. Nouvelle
fonctionnalité
Scénario #1 : Développer une
nouvelle fonctionnalité
1. Écrire un test pour une nouvelle
fonctionnalité (tests KO)
2. Lancer le test, il échoue (tests KO)
3. Écrire assez de code pour passer le
test (tests OK)
4. Refactoring pour faire le code de
meilleure qualité (tests OK)
35. Correction
de bug
Scénario #2 : Correction de bug
/ erreur
1. Écrire un test du code avec un bug
- documentation (tests KO)
2. Faire les modification, le test
passe (tests OK)
3. Refactoring (tests OK)
36. Refactoring
Scénario #3 : Refactoring
1.Écrire/modifier les tests
unitaires (tests KO)
2.Écrire le code (tests KO)
3.Refactoring (tests OK)
37. Legacy code
Scénario #4 : Legacy code
▸Écrire des tests unitaires
pour commencer à
comprendre du vieux code
ou un système déjà en place
38. Learning
Scénario #5 : Learning
▸Utiliser une nouvelle API
▸Faire un nouvel algorithme
▸Le test est maintenant une
base de savoir réutilisable
41. Diagram AAA "Arrange-Act-Assert"
A pattern for arranging and
formatting code :
1.Arrange all necessary
preconditions and inputs.
2.Act on the object or method
under test.
3.Assert that the expected results
have occurred.
Diagram
"AAA" 1/3
43. Diagram
"AAA" 3/3
Avantages:
▸ Séparation clair de ce qui est
testé : entrée, fonction,
résultat
▸ Met la priorité aux paliers
nécessaires dans le test du
code
▸ Ne pas faire trop de choses
différentes à la fois
46. Continuous
Integration
"In software engineering, continuous integration
(CI) is the practice of merging all developer
working copies to a shared mainline several times
a day.
Grady Booch first named and proposed CI in his
1991 method, although he did not advocate
integrating several times a day. Extreme
programming (XP) adopted the concept of CI and
did advocate integrating more than once per day -
perhaps as many as tens of times per day."
-- wikipedia
47. Extreme Programming :
▸ Objectif : produire du code de qualité de
manière productive
▸ Cycles de développement courts
▸ Changer le code n'affecte pas les
fonctionnalités
▸ Le code est au centre
▸ Unit tests / acceptance tests (client)
▸ Communication, simplicity, feedback, and
courage
▸ Peer-programming
XP
48. Nouvel
arrivant : unit
test
Nouvel arrivant :
▸Permet de se familiariser
avec du code.
▸Documentation et
spécification de comment
utiliser le code
49. Contrôle de
la régression
En cas de gros changement de
codebase : outils contre la
Régression
Lors de :
▸Refactoring
▸De grands changements
51. Libcheck 1/2
#include <stdlib.h>
#include <check.h>
#include "../src/money.h"
START_TEST(test_money_create)
{
Money *m;
m = money_create(5, "USD");
ck_assert_int_eq(money_amount(m), 5);
ck_assert_str_eq(money_currency(m), "USD");
money_free(m);
}
END_TEST
More on https://github.com/libcheck/check
52. Libcheck 2/2
Running suite(s): Money
0%: Checks: 1, Failures: 1, Errors: 0
check_money.c:9:F:Core:test_money_create:0: Assertion
'money_amount (m)==5' failed:
money_amount (m)==0, 5==5
FAIL: check_money
=====================================================
1 of 1 test failed
Please report to check-devel AT lists.sourceforge.net
=====================================================
53. Ruby on
Rails
Rails test
require 'test_helper'
class modelTest < ActiveSupport::TestCase
test "the truth" do
assert true
end
End
bin/rake test test/models/project_test.rb
Run options: --seed 227
# Running:
.
Finished in 0.173677s, 5.7578 runs/s, 5.7578 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
54. Available
assertions
Assertion Purpose
assert( test, [msg] ) Ensures that test is true.
assert_not( test, [msg] ) Ensures that test is false.
assert_equal( expected, actual,
[msg] )
Ensures that expected == actual is
true.
assert_not_equal( expected,
actual, [msg] )
Ensures that expected != actual is
true.
assert_same( expected, actual,
[msg] )
Ensures that
expected.equal?(actual) is true.
assert_not_same( expected,
actual, [msg] )
Ensures that
expected.equal?(actual) is false.
assert_nil( obj, [msg] ) Ensures that obj.nil? is true.
assert_not_nil( obj, [msg] ) Ensures that obj.nil? is false.
assert_empty( obj, [msg] ) Ensures that obj is empty?.
*http://guides.rubyonrails.org/testing.html
55. Rails
Fixtures
Fixtures are a way of organizing data that you
want to test against; in short, sample data.
rubyonrails:
id: 1
name: Ruby on Rails
url: http://www.rubyonrails.org
google:
id: 2
name: Google
url: http://www.google.com