Tester une Java Google Cloud Function

Tester une Java Google Cloud Function

Jusqu’il y a peu de temps, tester une Google Cloud Function écrite en Java pouvait se faire via l’invoker fournit par le SDK des Google Cloud Functions mais pas via un test unitaire. Mais cela à changé récemment !

Prenons comme exemple la fonction HTTP suivante :

public class HelloHttpFunction implements HttpFunction { 
    @Override
    public void service(HttpRequest httpRequest, HttpResponse httpResponse) 
            throws Exception { 
        Writer writer = httpResponse.getWriter();
        writer.write("Hello World");
    }
}

Après packaging de celle-ci dans un über JAR, nous pouvons télécharger l’invoker Google Cloud function via la commande Maven suivante :

mvn dependency:copy \
  -Dartifact='com.google.cloud.functions.invoker:java-function-invoker:1.1.1' \
  -DoutputDirectory=.

Puis l’utiliser pour démarrer la fonction en local :

java -jar java-function-invoker-1.1.1.jar \
  --classpath target/hello-world.jar \
  --target org.example.HelloHttpFunction

Notre fonction est alors testable sur le port 8080.

Hélas, ceci n’est pas pratique dans une optique d’intégration continue où nous voudrions exécuter des tests automatisés avec JUnit par exemple.

Heureusement, l’invoker de fonction est un projet Open Source de Google et votre serviteur a proposé une PR pour permettre l’utilisation de celui-ci via des tests automatisés en proposant une méthode stop qui était manquante.

En utilisant sa dernière version, nous pouvons ajouter l’invoker en dépendance Maven de notre projet pour l’utiliser dans un test unitaire.

<dependency>
    <groupid>com.google.cloud.functions.invoker</groupid>
    <artifactid>java-function-invoker</artifactid>
    <version>1.1.1</version>
    <scope>test</scope>
</dependency>

Nous pouvons alors créer des tests JUnit.
Par exemple pour notre fonction HTTP HelloHttpFunction nous aurons le test suivant :

class HttpFunctionTestCase {
    @Test
    public void test() throws Exception {
        // start the invoker without joining to avoid blocking the thread
        Invoker invoker = new Invoker(
                8081,
                "org.example.HelloHttpFunction",
                "http",
                Thread.currentThread().getContextClassLoader());
        invoker.startTestServer();

        // test the function using REST-assured
        when()
                .get("http://localhost:8081")
                .then()
                .statusCode(200)
                .body(is("Hello World!"));

        // stop the invoker
        invoker.stopServer();
    }
}

Le framework REST-assured est utilisé ici pour faciliter l’écriture de test HTTP.

Le troisième paramètre à passer lors de l’instanciation de l’invoker est le type de fonction à tester, tous les types de fonction sont supportés :

  • http : pour les fonctions HTTP;
  • event : pour les fonctions backgound;
  • cloudevent : pour les fonctions Cloud Events.

Pour tester une fonction background qui réagit à un événement Cloud Storage, on va devoir envoyer un événement au format JSON via un POST HTTP sur l’URL de l’invoker. Nous pouvons utiliser REST-assured pour cela comme nous avons fait pour une fonction HTTP.

class BackgroundStorageFunctionTestCase {
    @Test
    public void test() throws Exception {
        // start the invoker without joining to avoid blocking the thread
        Invoker invoker = new Invoker(
                8081,
                "org.example.BackgroundStorageFunction",
                "event",
                Thread.currentThread().getContextClassLoader());
        invoker.startTestServer();

        // test the function using REST-assured
        given()
                .body("{\"data\":{\"name\":\"hello.txt\"}}")
                .when()
                .post("http://localhost:8081")
                .then()
                .statusCode(200);

        // stop the invoker
        invoker.stopServer();
    }

En conclusion, grâce à la version 1.1.1 de l’invoker de fonction Goole Cloud, nous pouvons tester nos fonctions automatiquement avec JUnit5, et s’assurer de leur qualité et leur non-régression fonctionnelle dans un workflow de CI.

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.