La qualité a souvent besoin d’un plan de test clair pour s’assurer que l’ensemble des spécifications a été vérifiée. Quand ces tests sont effectués de manière automatisée, il peut être intéressant de générer leur plan à partir de la documentation du code.

L’idée est la suivante : plutôt que d’avoir un document word qui liste les tests à effectuer sur un logiciel, puis de faire développer lesdits tests, puis d’essayer tant bien que mal de garantir la jonction entre les deux via un suivi manuel qui induit probablement des erreurs, on génère le plan de test depuis le code des tests. Comme ça, tout test non implémenté n’apparait pas ans le plan de test.

On peut ensuite s’assurer de la couverture des tests via des outils de tracabilité classiques type Reqtify, et figer un plan de test dans un système de gestion documentaire lorsqu’on effectue la phase officielle de test.

Voici un exemple qui, partant d’une suite de test python, génère un plan de test associé au format word.

L’utilisation d’un système de template permet de plus d’écrire les explications générales dans celui ci : seule la liste exhaustive des tests est générée.

Lister les tests

La première étape pour générer une documentation sur la liste des tests consiste à récupérer, via pytest, la liste des tests effectués.

La documentation de pytest nous donne la liste des hooks disponibles. Il suffit de créer un fichier conftest.py, ou de se lancer dans la création d’un plugin, et de déclarer la fonction suivante :

def pytest_collection_modifyitems(config, items):
    test_list = [ item.function for item in items]

pour obtenir la liste des fonctions de tests collectées. On a alors accès aux attributs utilisables suivants sur nos tests :

  • __name__ : nom de notre fonction de test
  • __annotations__ : un dict ou on met les méta données de la fonction (voir pep-3107). En théorie c’est la doc des arguments et leur type, mais on peut le détourner un petit peu ici.
  • __doc__ : la doc de la fonction. Généralement utilisée pour générer la documentation associée, avec sphinx par exemple.

Ajouter des méta données aux tests

Pour ajouter des informations utiles (Spécification couverte, Id du test, Titre de celui ci, etc), on peut utiliser un décorateur, qui ajoutera quelques champs dans l’attribut __annotations__ de nos fonctions, comme dans l’exemple ci dessous.

def annotate(new_annotations):
    def decorator(fun):
        fun.__annotations__.update(new_annotations)
        return fun
    return decorator

@annotate({"title":"Mon premier test",
    "cover":["REQ123", "REQ456"],
    "testid":"TES123"})
def test_one():
    """ La documentation de mon test. Elle apparaitra dans mon plan,
    donc je veux qu'elle soit aussi proche que possible de la réalité de ce qu'il fait
    """
    assert True

Si on inspecte la fonction test_one, on aura accès aux informations suivantes :

test_one.__name__
>> 'test_one'
test_one.__annotations__
>> {'title': 'Mon premier test', 'cover': ['REQ123', 'REQ456'], 'testid': 'TES123'}
test_one.__doc__
>> " La documentation de mon test. Elle apparaitra dans mon plan,
 donc je veux qu'elle soit aussi proche que possible de la réalité de ce qu'il fait\n    "

Il ne reste plus qu’à générer un document à partir de ces informations.

Générer un rapport contenant les méta-données

On utilisera l’exellent package python-docx-template, qui permet de compléter un document word existant, via un templating facon Jinja2.

Créer un template Jinja2 basé sur du docx

L’idée est simplement d’écrire votre document tel que vous le voulez, avec le style etc, mais de remplacer toutes les variables qui viendront des tests avec un syntaxe jinja2. C’est bien expliqué dans la documentation du package, je ne vais donc pas revenir dessus.

Le template pourrait ressembler à ceci (simplement chaque élément a son propre style dans le document word initial) :

Exemple de doc

{{ company_name }}

{% for item in items %}
{{ item.__annotations__['title'] }}
{{ item.__doc__ }}

{% endfor %}

Les éléments entre doubles accolades sont des fonctions ou des variables qu’on passera au moteur de template.

Générer le rapport

On génère le rapport avec les quelques lignes suivantes :

import pytest
from docxtpl import DocxTemplate


def pytest_collection_modifyitems(config, items):

    test_list = [ item.function for item in items] # crée la liste des tests

    doc = DocxTemplate("template.docx")
    # crée le dictionnaire "contexte" des objets python qu'on va
    # pouvoir utiliser dans le .word servant de template
    context = { 'company_name' : "World company", "items" : test_list}
    doc.render(context)
    doc.save("generated_doc.docx")

Ce qui nous donne si on avait deux tests :

image

Conclusion

Nous avons présenté un méthode simple, qui je l’espère peut permettre d’améliorer un peu certains process qualités qui peuvent être lourds.

Cela s’applique principalement dans un cadre ou le poid de la documentation word ou pdf est importante, car tout les outils et les procédures mis en place sont basés là dessus.

Si l’on doit partir de zéro pour son système qualité, il peut être intéressant de s’orienter vers des solutions en ligne, comme Tuleap, qui sont pensé pour intégrer la qualité dans le développement logiciel.

On peut aussi mentionner qu’il existe des outils pour définir des comportements (orientés BDD, ie Behavior Driven Developpement), comme cucumber (ou behave en python), et générer du code de test à partir de spécifications écrites dans un format relativement lisible. Cela peut être une alternative à pytest, mais les mêmes pratiques sont appliquables.