IEA – une stratégie de test basée sur des fichiers pour les transformations de documents
par Douglas Campbell, ingénieur principal
I/E/A – entrée/attendu/réel
Si vous pouvez fournir des implémentations pour l'ensemble de fonctions ci-dessous,
// defines how to go from file to an instance of IN
abstract IN loadInput(File input);
// defines how to go from file to OUT instances
// throw FNF whenever there’s no expected file.
abstract OUT loadOutput(File expected) throws FileNotFoundException;
// invoked upon missing expected file or if actual != expected
abstract void storeResult(OUT result, File resultFile);
beaucoup peut être fait pour prendre la corvée de tester les transformations de documents et de maintenir un ensemble robuste de tests.
En bref, il devient trivial écrire des cas de test comme des fichiers plutôt que des fonctions.
Je préfère grandement cette approche pour tester la transformation de documents que mucking avec le code de test. D'abord, un peu de fond.
Fond
Une grande partie du code que j'ai écrit au fil des ans a à son cœur de changer les documents d'un format dans un autre. Par documents, je parle de toute variété de JSON, XML, Avro, Tab délimité, YAML, que ce soit-tout et n'importe quoi et tout et de retour.
Quand on lui demande de coder des trucs comme ça, de nombreux yeux de dev simplement renverser à l'horreur de l'écriture quelque chose de si trivial que la cartographie d'un champ à l'autre, haut-boîtier, il fusion avec une autre valeur lue à partir d'une source de données externes, puis la mise dans un autre Représentation.
Cette nouvelle représentation peut avoir peu de ressemblance avec le doc initial. C'est la nature de la bête.
En bref, les exigences de conduite des transformations de données sont complètement arbitraires!
Je pense que c'est la raison pour laquelle certains développeurs détestent ce genre de choses. Ils prennent de courtes coupes et de jeter les choses dans le code de test qui ressemblent à ceci...
//CHECKSTYLE:OFF
private static final String CLICK = "a horrendously ugly line of input from an access log";
//CHECKSTYLE:ON
Et quand il est temps de tester une "impression" deviner ce qui se passe. Ugh – Testez l'entrée en ligne comme variables de chaîne. Spider sens immédiatement activé lors de la suppression de Checkstyle!
Une chose que j'ai appris, c'est que partout où il ya crainte et d'évasion, c'est exactement là où une paresse excessivement énergique est nécessaire. Reculez. Rendez-le mort simple et se débarasser des rames et des rames de la logique et ou du code dupliqués. Ecrire une fonction pour exécuter sur un dossier entier complet de tests
// test folder of tests and fail entire run if any fail.
public void testFolder(File testfolder, Function<IN, OUT> converter) {
for (File test: testfolder.listFiles(testFileFilter)) {
if (!testSingle(test, converter)) {
fail("expected != actual - actual " +
"results saved in .actual file");
};
}
}
Alors qu'en est-il de cette fonction testSingle? Très simple avec les trois fonctions définies au début du blog.
// test a single test
private boolean testSingle(File test, Function converter) {
IN input = loadInput(test);
OUT actual = converter.apply(input);
OUT expected = null;
// only create if no expected file or result is different.
File actualFile = new File(test.getParent(),
test.getName() + ".actual");
try {
expected = loadOutput(new File(test.getParent(),
test.getName()
+ ".expected"));
} catch (FileNotFoundException ex) {
// we haven't got expected file - no biggie
// we can turn this into an expected file once
// satisfied with it.
storeResult(actual, actualFile);
}
return false;
// we've got something to compare
if (!actual.equals(expected)) {
// fail and save the actual file for command
// line diffing
storeResult(actual, actualFile);
return false;
}
return true;
}
Avantages divers de cette approche
Pour les documents texte et ASCII, l'utilitaire diff est immédiatement disponible pour comparer les échecs de test
Vous n'avez pas à écrire le code de test pour générer ce que votre sortie attendue est. Il suffit d'ajouter votre exemple d'enregistrement dans le dossier tests, exécuter les tests, et la sortie réelle est généré dans un nouveau fichier avec. extension réelle
Vous avez un moyen immédiat d'exécuter votre code sur les enregistrements qui vous ont causé des problèmes dans la production. Encore une fois, déposez l'enregistrement problématique dans votre dossier de test et exécutez le test.
Si votre équipe décide de créer un convertisseur flambant neuf ou d'utiliser une autre bibliothèque JSON, tous vos tests sont exprimés en fichiers indépendants de la langue. Vous pouvez les porter en avant.
Trucs pour obtenir droit à l'avant
Tout d'abord, veillez à rendre votre logique de transformation apatride. Essentiellement, les transformations de documents qui impliquent des appels hors processus doivent être retravaillées afin de séparer la récupération des données brutes de ce qui est fait pour elle.
Deuxièmement, commencer à faire cela dès le début dans le cycle de vie du module de code ou App. Les appétits sont généralement assez maigre pour tourner en arrière et re-travail vieux tests de dégoût.
Étape suivante
Une prochaine étape pour nous est de l'emballer sous la forme d'un pack de test open source. Qui sait, ça peut même arriver plus tôt si on s'y intéresse un peu.