Comment mettre à jour sa chaîne d’intégration continue pour y intégrer des tests fonctionnels d’une API REST**?**
Une API permet d’exposer à des clients des méthodes et des objets de manière simple, mais le client d’une API doit être assuré de la stabilité des signatures et du comportement pour une version donnée. Il est donc intéressant de vérifier qu’une API reste stable et respecte son contrat d’interface dans le temps. Pour cela il faut créer des tests fonctionnels et automatiser leur lancement pour qu’ils soient exécutés lors de l’intégration continue. Cet article présente comment, avec SoapUI, Maven et Jenkins, on peut répondre au besoin d’automatisation des tests d’intégration d’une API REST.
SoapUI
Pour créer des tests fonctionnels, on peut utiliser SoapUI qui intègre dans ses dernières versions des tests steps spécifiques aux API REST et n’est donc plus limité aux requêtes SOAP.
Les tests steps sont, comme leur nom l’indique, les différentes étapes d’un test réalisé avec SoapUI, et peuvent être l’appel d’un service, une branche conditionnelle sur un résultat, l’exécution d’un script groovy…
Dans cet exemple, on appelle un service qui renvoie un objet JSON de la forme :
{
"one": "two",
"key": "value"
}
Pour vérifier que le retour du service est conforme, il y a deux stratégies:
Par fichier de référence
Le script groovy suivant permet lire un fichier de référence et de comparer le contenu de la réponse du service :
import groovy.json.JsonSlurper
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def projectDir = groovyUtils.projectPath
def defaultPathBase = new File( "." ).getCanonicalPath()
// Groovy Script Engine permet de charger des scripts externes
GroovyScriptEngine gse = new GroovyScriptEngine(projectDir)
//chargement d'un script externe qui parse le json
externalScript = gse.loadScriptByName("FileUtils.groovy")
fileUtils = externalScript.newInstance()
//chargement du fichier de reference
def path = projectDir + '/' + 'expected-json-responses/v1.0/expected.json'
def expected = fileUtils.readFromFile(path)
//utilisation du langage d'expression de SoapUI pour recuperer le conenu de la reponse HTTP
def actual = context.expand( '${getJson#Response}' )
assert expected == actual : "Response didn't match expected json"
Si la réponse ne correspond pas au fichier, le test s’affichera en erreur.
En comparant les attributs du JSON retourné
SoapUI permet de définir des assertions de type “XPATH Assertion” qui vérifient qu’une valeur identifiée par un chemin XPath est correcte.
Ici on vérifie que dans la réponse JSON, la valeur associée à “key1” est bien “value1”
Si la réponse ne correspond pas au résultat attendu, le test s’affichera en erreur.
En combinant ces deux types d’assertions et en utilisant les fonctionnalités de SoapUI comme les propriétés et les méthodes d’accès aux valeurs de ces propriétés on peut créer des tests complexes qui valident le comportement de notre API pour un client.
Automatisation
Maintenant que nos tests sont écrits, il faut automatiser le lancement et les rapports de test.
Pour cela nous allons utiliser Maven et Jenkins pour s’intégrer facilement dans une chaine d’intégration continue existante.
Maven
A la racine de notre projet, on crée un fichier pom.xml contenant les sections suivantes :
On ajoute le pluginRepository de SoapUI :
<pluginRepositories>
<pluginRepository>
<id>smartbear-sweden-plugin-repository</id>
<url>http://www.soapui.org/repository/maven2/</url>
</pluginRepository>
</pluginRepositories>
Et on configure le plugin comme suit :
<plugin>
<groupId>com.smartbear.soapui</groupId>
<artifactId>soapui-pro-maven-plugin</artifactId>
<!-- version de soapui -->
<version>4.6.1</version>
<dependencies>
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<version>1.2.1</version>
</dependency>
</dependencies>
<executions>
<execution>
<!-- Lancer via mvn test -->
<id>REST API Tests</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- Nom du fichier projet SoapUI -->
<projectFile>Rest-API-Tests-soapui-project.xml</projectFile>
<outputFolder>
<!-- Generer des rapports de test -->
${project.build.directory}/surefire-reports
</outputFolder>
<junitReport>true</junitReport>
<printReport>true</printReport>
<!-- Conf specifique au projet -->
<settingsFile>soapui-settings.xml</settingsFile>
<soapuiProperties>
<property>
<!-- Logs -->
<name>soapui.logroot</name>
<value>
${project.build.directory}\soapui-logs\
</value>
</property>
</soapuiProperties>
</configuration>
</plugin>
Cette configuration permet de générer des rapports comme le ferait un test unitaire JUnit.
Le fichier soapui-settings.xml contient l’équivalent des options disponibles dans les paramètres de la GUI de SoapUI, par exemple la configuration d’un proxy, la compression des réponses, le pretty-printing…
On lance les tests avec un simple “mvn test” (l’exécution du test nécessite qu’un conteneur réponde aux URI auxquelles le script tente d’accéder) et on peut voir dans le rapport d’exécution si tous les tests sont validés :
Il ne nous reste plus qu’à configurer Jenkins pour lancer le build Maven.
Jenkins
Jenkins nous permet de lancer les tests à un intervalle défini – par exemple une fois par jour – et d’afficher les rapports de tests.
Notre build se configure comme un projet Maven classique, avec les goals “clean test”.
Et on peut vérifier les rapports de test en cas d’erreur :
On a donc automatisé le lancement de nos tests, et on peut conditionner le déploiement d’une version de développement de notre API à la réussite des tests d’intégration.