vendredi 18 mars 2011

Tests unitaires, HTTP et Java

S'il vous est déjà arrivé d'écrire du code qui effectue des requêtes http, alors il vous est arrivé d'écrire des tests automatisés pour tester ce code (mais si, voyons !).

Mais alors comment faites-vous ?

Dans le cas d'un développement en Java (mais pas seulement), une solution est d'introduire, dans la classe testée, des méthodes non privées qui font effectivement les appels HTTP puis, dans les tests, de truquer ces méthodes (d'où la nécessité qu'elles ne soient pas privées) de façon à simuler différents retours du serveur web ou vérifier ce que votre code tente de transmettre au serveur.

C'est ce que je faisais dans les tests de soap-dust mais sans être vraiment satisfait de mon code.

Finalement j'ai choisi une méthode qui me parait plus élégante.

J'ai définit des urls au format test: qui simulent des urls http:. Dans mes tests, je configure le code que je veux tester pour qu'il utiliser des urls test: plutôt que des urls http:.

Dans une url test:, je suis directement capable de définir le statut HTTP lorsqu'on requête cette url, de même que les données qu'on obtient. Cerise sur le gâteau, à la fin du test, je peux récupérer les données qu'un client aurait tenté de transmettre à un serveur via cette url.

Exemple :


HttpURLConnection connection = (HttpURLConnection) new URL("test:status:500").openConnection();
assertEquals(500, connection.getResponseCode());

HttpURLConnection connection = (HttpURLConnection) new URL("test:status:200;file:hello.txt").openConnection();
assertStreamContent("Hello World !", connection.getInputStream);

byte[] written = new byte[] {1, 2, 3, 4};
HttpURLConnection connection = (HttpURLConnection) new URL("test:").openConnection();
OutputStream out = connection.getOutputStream();
out.write(written);
out.flush();
out.close();
assertTrue(Arrays.equals(written, Handler.saved.get("test:").toByteArray()));


Pour que les URLs test: soient reconnues par la jvm, il suffit de créer un classe test.Handler dans le package de votre choix puis de déclarer ce nouvel handler dans la jvm. Par exemple dans le cas des tests de soap-dust :


String handlers = System.getProperty("java.protocol.handler.pkgs");
if (handlers == null) handlers = "";
handlers += "|soapdust.urlhandler";
System.setProperty("java.protocol.handler.pkgs", handlers);


Grâce à cela, j'ai pu à nouveau rendre privée les méthodes que j'avais exposée uniquement pour les tests et ainsi j'ai eu plus de liberté dans la réorganisation de mon code.

Pour plus de détails, consultez :


Ce gestionnaire d'url test: est en version alpha et livré avec soap-dust.