JPF'07

Le Document-Driven Developpement (DDD)

Author:Tarek Ziadé <tarek@ziade.org>
Date:$Date: 2007-02-21$
License:CC-By-SA 2 license

Qui suis-je ?

Pourquoi cette présentation?

Objectifs:

important En un mot: comment développer agile en Python

Pourquoi cette présentation?

Objectifs secrets (ne pas montrer ce slide):

Le plan

Quelques définitions

Que veux dire le mot agile ?

Quelques définitions

Tentative de définition appliqué au développement:

C'est une méthodologie de programmation qui permet de rester réactif aux fréquentes modifications d'une base de code

Viens de l'Agile Manifesto (http://agilemanifesto.org/ [1])

[1]Le site ressemble à celui d'une secte, mais c'est une bonne secte wink

Quelques définitions

Les principes agiles peuvent s'appliquer à tout processus répétitif:

Quelques définitions

TDD == Test-Driven Development == Développement Dirigé par les Tests

Le plan

Partie 1

Le TDD avec Python

Les principes du TDD

Les principes du TDD

Exemple:

>>> def division(a, b):
...     return a / b

Essayons !

>>> def test_division():
...     if division(4, 2) == 2:
...         return 'OK'
...     else:
...         return 'Le processeur est moisi'
>>> test_division()
'OK'

Les principes du TDD

Chaque test concerne un aspect du code.

En voici un autre:

>>> def test_division2():
...     if division(4, 0) == 0:
...         return 'OK'
...     else:
...         return "C'est discutable..."
>>> test_division2()
Traceback (most recent call last):
...
ZeroDivisionError: integer division or modulo by zero

Les principes du TDD

Ca plante, changeons la fonction:

>>> def division(a, b):
...     if b == 0:
...         return 0
...     return a / b

relancons le test:

>>> test_division2()
'OK'

Les principes du TDD

Je change la fonction, je revalide les tests

Les principes du TDD

Encore plus fort: le test est écrit avant le code:

>>> def test_average():
...     if average(1, 2, 3) == 2:
...         return 'OK'
...     else:
...         return 'Houston we have a problem'
>>> test_average()
Traceback (most recent call last):
...
NameError: global name 'average' is not defined

Les principes du TDD

Le code à présent:

>>> def average(*args):
...     return sum(args) / len(args)

Le test à nouveau:

>>> test_average()
'OK'

-> Les tests devraient être écrits avant le code

-> Bien souvent ils le sont en même temps ou juste après

Les principes du TDD

Le TDD offre:

Les principes du TDD

Jean-Charles dit:

"Les tests. Quelle perte de temps. C'est juste un jouet pour les langages interprétés"

Bruce Eckel dit:

"If it's not tested, it's broken"

Les principes du TDD

Bruce a raison.

Partie 1

Le TDD avec Python

Comment écrire des tests

Python est batteries included. On y trouve:

important Il existe plein d'autres outils tiers de tests

Comment écrire des tests

unittest fourni des outils pour l'écriture des tests:

Comment écrire des tests

TestCase fourni:

Comment écrire des tests

Ecrire une suite de tests == dériver de TestCase:

>>> import unittest
>>> class DivisionTestCase(unittest.TestCase):
...
...     def test_one(self):
...         self.assertEquals(division(4, 2) , 2)
...
...     def test_two(self):
...         self.assert_(division(4, 0) == 0)
...

Un test == une méthode préfixée de test

Comment écrire des tests

Les tests peuvent être:

Comment écrire des tests

Exemple de module:

import unittest
from division import division

class DivisionTestCase(unittest.TestCase):

     def test_one(self):
         self.assertEquals(division(4, 2) , 2)

     def test_two(self):
         self.assert_(division(4, 0) == 0)

def test_suite():
    suite = unittest.TestSuite()
    suite.addTests(unittest.makeSuite(DivisionTestCase))
    return suite

if __name__ == '__main__':
    unittest.main(defaultTest='test_suite')

Comment écrire des tests

Lancement des tests:

dabox:~ tarek$ python test_division.py
..
------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

Comment écrire des tests

Lancement des tests, avec une erreur:

dabox:~ tarek$ python test_division.py
F.
==================================================================
FAIL: test_one (__main__.DivisionTestCase)
------------------------------------------------------------------
Traceback (most recent call last):
File "test_division.py", line 7, in test_one
self.assertEquals(division(4, 2) , 3)
AssertionError: 2 != 3

------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=1)

Partie 1

Pour aller plus loin:

-> Comment organiser les tests dans un projet Python

Partie 1

Sans les tests:

media/sleeping.jpg

Partie 1

Avec les tests:

media/happy_1.jpg

Partie 1

Avec les tests:

media/happy_2.gif

Le plan

Partie 2

Les doctests

Les doctests

Exemple de doctest inline:

def somme(a, b):
    """ calcul la somme

    >>> somme(1, 3)
    4
    >>> somme(2, 2)
    4
    """
    return a + b

Les doctests

smile Les exemples sont directement disponibles

sad Le code devient dur à lire

Les doctests

Solution: séparer les doctests dans un fichier texte

Les doctests

Exemple de doctest séparé. Fichier calc.py:

def somme(a, b):
    """ calcul la somme
    """
    return a + b

Fichier calc.txt:

>>> from calc import somme
>>> somme(1, 3)
4
>>> somme(2, 2)
4

Les doctests

Un fichier doctest devient un test unitaire grâce au module doctest:

import doctest
import unittest

def test_suite():
    suite.append(doctest.DocFileTest('calc.txt'))
    return unittest.TestSuite(suite)

if __name__ == '__main__':
    unittest.main(defaultTest='test_suite')

Les doctests

doctests + tests classiques == campagne de test

Le plan

Partie 3

Le Document-Driven Development

Principe:

Les doctests séparés peuvent aussi être des documents

Documentation

Chaque doctest == alternance de code et d'explications:

Module calc

Le module calc contient une fonction pour faire des sommes:

    >>> from calc import somme

Cette fonction prends deux paramètres:

    >>> somme(1, 3)
    4
    >>> somme(2, 2)
    4

Documentation

smile Promiscuité de la documentation

smile La documentation évolue en même temps que le code

smile Le développeur utilise la doc. pour concevoir les tests

smile La documentation du projet est conçue en partie par ce biais

Documentation

important Un doctest doit rester un document: ne pas le noyer dans des test fixtures (mise en place pour les tests)

important Les doctests montrent des exemples publics de code

important Les tests unitaires classiques s'occupent du reste

Documentation

-> Demo: construction d'un module de calcul

Documentation

Pour aller plus loin:

-> utilisation du reSTructuredText dans les documents

Conclusion

Questions ?

Ressources

Ressources

Sortie le 16 aout:

media/guide.png