Automatiser les tests fonctionnels d’une API REST

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…

script_assertion_valid.png

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.

xpath_assertion.PNG

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 :

mvn.png

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”.

conf_jenkins.PNG

Et on peut vérifier les rapports de test en cas d’erreur :

error.png

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.