Intégrer GreenPepper dans TFS
À ma gauche, GreenPepper, un outil de tests fonctionnels, destiné aux MOA et leur permettant d’exprimer les spécifications sous forme de tests exécutables.
À ma droite, Team Foundation Server, usine de construction et de livraison de logiciel.
L’idée : lorsqu’un développeur effectue un check-in de son code, les tests GreenPepper sont lancés et le build échoue en cas de problème.
Comment faire ?
1 Configurer GreenPepper
La configuration de GreenPepper est très bien expliquée sur leur site, je vais donc me contenter d’un renvoi vers la page idoine : http://greenpeppersoftware.com/confluence/display/GP/System+Under+Test+Configuration
Quelques précisions cependant :
- Bien penser à choisir le runner .Net (sauf si vous faites du Java, mais dans ce cas, pourquoi TFS ?)
- Il faut créer un SUT (system under test) par build que vous voulez mettre en place. Par exemple, si vous souhaitez créer un build par environnement qui va vérifier que les tests GreenPepper sont au vert avant de déployer, il faut créer autant de SUT que d’environnements
- Chaque SUT doit définir un chemin différent pour la localisation des binaires testés. Une solution qui fonctionne bien consiste à créer dans votre répertoire de drop un répertoire dédié à ce build. Par exemple, si vous avez un build nommé ‘integration’ et que votre répertoire de drop se nomme [\MonNASDrops](file:///\MonNASDrops), le répertoire dédié à GreenPepper pourra être [\MonNASDropsIntegrationGreenPepper](file:///\MonNASDropsIntegrationGreenPepper).
2 Configurer TFS
Nous allons à présent modifier le build template de TFS pour y intégrer la copie des binaires dans le répertoire défini par le SUT ainsi que l’invocation du runner GreenPepper et la récupération des résultats
2.1 Modifier le build template
Commençons par rappeler la règle d’or : on ne travaille jamais sur le DefaultTemplate fourni par défaut mais toujours sur une copie.
Voilà la séquence à insérer :
Et quelques détails :
- Tout est englobé dans un try/catch, afin de s’assurer que le build ne s’arrête pas en plein milieu
- L’exécution de GreenPepper est protégée par un booléen qui est un argument du build. Cela permet d’utiliser le même build template partout, y compris sur les environnements pour lesquels vous ne voulez pas exécuter GreenPepper.
- Le chemin dans lequel vont se trouver les binaires (défini par exemple à Path.Combine(BuildDetail.DropLocationRoot, BuildDetail.BuildDefinition.Name, "GreenPepper")) est alors détruit. Cela est nécessaire pour évacuer les résidus des précédents builds.
- On copie ensuite l’ensemble des binaires issus du build dans le répertoire GreenPepper. TFS a cette particularité de mettre à plat toutes les sorties de projet dans le même répertoire. On trouvera ainsi dans le build output non seulement vos DLL mais également leurs dépendances (sauf si elles sont dans le GAC).
- Il ne reste plus ensuite qu’à lancer GreenPepper à l’aide d’un InvokeProcess. Pour ce faire, nous allons exécuter un batch qui va retourner 0 (tout va bien) si aucun test n’échoue ou une valeur différente en cas d’échec
2.2 Le batch de lancement de GreenPepper
Commençons par le batch :
@ECHO OFF
SET GPPATH=C:Confluencegreenpepper-open-net-2.9-V4.0
SET EXECUTABLE=%GPPATH%\GreenPepper.exe
REM SET BUILDSOURCE=C:\Drops\Homologation\GreenPepper
SET BUILDSOURCE=%1
SET CLASSPATH="
SET CLASSPATH=%CLASSPATH%%GPPATH%\CookComputing.XmlRpc.dll;
SET CLASSPATH=%CLASSPATH%%GPPATH%\GreenPepper.Core.dll;
SET CLASSPATH=%CLASSPATH%%GPPATH%\GreenPepper.exe;
SET CLASSPATH=%CLASSPATH%%GPPATH%\GreenPepper.Extensions.dll;
REM SET CLASSPATH=%CLASSPATH%%BUILDSOURCE%\LG.GreenPepperTest.dll;
SET CLASSPATH=%CLASSPATH%%BUILDSOURCE%\%2;
SET CLASSPATH=%CLASSPATH%"
SET REPOSITORY="
SET REPOSITORY=%REPOSITORY%GreenPepper.Repositories.GreenPepperRepository
SET REPOSITORY=%REPOSITORY%;http://vmlgdev1:8585/confluence/rpc/xmlrpc?handler=greenpepper1&sut=
REM SET REPOSITORY=%REPOSITORY%HomologationBuild
SET REPOSITORY=%REPOSITORY%%3
SET REPOSITORY=%REPOSITORY%"
SET SUD=GreenPepper.Fixtures.PlainOldSystemUnderDevelopment
SET INPUT=Confluence-ElGeneral
SET OUTPUT="%BUILDSOURCE%\result\"
%EXECUTABLE% --stop --xml -a %CLASSPATH% -s -r %REPOSITORY% -f %SUD% %INPUT% %OUTPUT%
En commentaires se trouvent des valeurs d’exemple liées à mon dernier projet. En rouge se trouvent l’adresse du serveur GreenPepper et le nom du projet GreenPepper (visible dans la configuration de l’espace confluence), à modifier évidemment en fonction de votre configuration.
Plusieurs remarques :
- Ce script prend trois paramètres : le chemin dans lequel GreenPepper va aller chercher les binaires, la DLL contenant les fixtures et le nom du SUT utilisé (qu’il faut aller chercher dans la configuration GreenPepper)
- Le chemin d’installation de GreenPepper ainsi que le serveur GreenPepper et le nom du projet sont fixés en dur. C’est un choix, qu’il vous appartient de modifier ou non.
- Tous les chemins sont locaux. Je n’ai pas testé avec des chemins UNC, mais cela a pour inconvénient que le répertoire de drops doit être connecté à une lettre de lecteur sur la machine GreenPepper
- Le ClassPath contient 4 DLL essentielles à GreenPepper pour .net, ainsi que votre DLL de fixture
- J’utilise le SUD par défaut de GreenPepper, qui est suffisant dans la plupart des cas.
- Les résultats sont produits sous forme de fichier XML (option --xml) dans le répertoire result, situé dans le répertoire où se trouvent les binaires. Attention à ne pas indiquer un chemin relatif, car TFS exécute par défaut les processus avec comme chemin courant C:WindowsSystem32, dans lequel il n’a probablement pas les droits d’écriture.
- L’option --stop demande à GreenPepper d’arrêter une fixture à la première erreur. On peut préférer avoir un rapport plus complet, c’est un choix à faire.
- On pourrait faire ça en une seule ligne directement dans TFS, mais ça serait un poil indigeste.
3 Finitions
3.1 Adaptation des pages de spécifications
Et c’est tout alors ? Non, il reste une subtilité qui a son importance : la façon d’exécuter. Elle est fondamentalement différente entre le batch présenté et un clic sur ‘execute’ dans l’interface web.
En effet, GreenPepper, lorsqu’on clique sur ‘Execute’, va exécuter le runner une fois pour chaque page de spécification, alors que le batch ne lance qu’un seul processus pour l’ensemble des spécifications. La conséquence ? Si vos tests GreenPepper utilisent des bouchons pour des services réseau ou une base de donnée en mémoire, ceux-ci ne seront par recréés entre chaque page de spécification.
Il faut donc penser à rajouter en tête de chaque page de spécifications une fixture qui va s’occuper de nettoyer la base mémoire (voire de la recréer) et de remettre dans leur état initial l’ensemble des bouchons utilisés par vos spécifications exécutables, faute de quoi vos pages de spécifications risquent d’échouer les unes après les autres parce que les données ne sont pas bonnes (voire d’échouer sur les INSERT en base pour cause d’IDs dupliqués).
3.2 Intégrer un rapport un peu plus complet à TFS
En l’état, vous aurez seulement un avis global sur GreenPepper (tout est vert/Au moins un test ne passe pas) sans plus de détail. Il faudra aller consulter les rapports d’exécution pour cela.
Si vous voulez un rapport plus complet, il faut rediriger la sortie du batch vers le log TFS (en ajoutant une activité WriteBuildMessage sur l’output de l’activité InvokeProcess), ce qui vous indiquera, par page de spécifications, le nombre de tests verts et rouges.
3.3 On a tué le parallélisme !
Et oui, c’est l’inconvénient de cette façon de faire. Supposez que vous lanciez deux fois le même build en parallèle. Si, pendant l’exécution de GreenPepper, le second build tente de supprimer le répertoire dans lequel se trouvent les binaires, soit il n’y arrive pas parce que c’est verrouillé, soit il y arrive (par chance) et le premier build voit son GreenPepper partir en erreur sur tous les tests.
D’où également l’importance de choisir un répertoire de binaires différent pour chaque build.