Dans mon projet actuel, j'ai du mal à trouver une bonne solution pour créer des tests d'intégration évolutifs sans effets secondaires. Une petite clarification sur la propriété sans effet secondaire: il s'agit principalement de la base de données; il ne devrait y avoir aucun changement dans la base de données une fois les tests terminés (l'état doit être conservé). Peut-être que l'évolutivité et la préservation de l'état ne se rejoignent pas, mais je veux vraiment pousser pour une meilleure solution.
Voici un test d'intégration typique (ces tests touchent la couche de base de données):
public class OrderTests {
List<Order> ordersToDelete = new ArrayList<Order>();
public testOrderCreation() {
Order order = new Order();
assertTrue(order.save());
orderToDelete.add(order);
}
public testOrderComparison() {
Order order = new Order();
Order order2 = new Order();
assertFalse(order.isEqual(order2);
orderToDelete.add(order);
orderToDelete.add(order2);
}
// More tests
public teardown() {
for(Order order : ordersToDelete)
order.delete();
}
}
Comme on pourrait l'imaginer, cette approche donne des tests extrêmement lents. Et, lorsqu'il est appliqué à l'ensemble des tests d'intégration, il faut environ 5 secondes pour tester uniquement une petite partie du système. Je peux imaginer que ce nombre augmente lorsque la couverture est augmentée.
Quelle serait une autre approche pour écrire de tels tests? Une alternative à laquelle je peux penser est d'avoir des types de variables globales (au sein d'une classe) et toutes les méthodes de test partagent cette variable. En conséquence, seules quelques commandes sont créées et supprimées; résultant en des tests plus rapides. Cependant, je pense que cela introduit un problème plus important; les tests ne sont plus isolés et il devient de plus en plus difficile de les comprendre et de les analyser.
Il se peut simplement que les tests d'intégration ne soient pas destinés à être exécutés aussi souvent que les tests unitaires; par conséquent, de faibles performances pourraient être acceptables pour ceux-ci. Dans tous les cas, ce serait formidable de savoir si quelqu'un a trouvé des alternatives pour améliorer l'évolutivité.
C'est le problème éternel auquel tout le monde est confronté lors de l'écriture de tests d'intégration.
La solution idéale, en particulier si vous testez en production, est d'ouvrir une transaction dans la configuration et de la reculer dans le démontage. Je pense que cela devrait répondre à vos besoins.
Lorsque cela n'est pas possible, par exemple lorsque vous testez l'application à partir de la couche client, une autre solution consiste à utiliser une base de données sur une machine virtuelle et à prendre un instantané dans la configuration et à y revenir dans le démontage (il ne prendre aussi longtemps que vous pourriez vous y attendre).
la source
Les tests d'intégration doivent toujours être exécutés par rapport à la configuration de production. Dans votre cas, cela signifie que vous devez avoir la même base de données et le même serveur d'applications. Bien sûr, pour des raisons de performances, vous pouvez décider d'utiliser une base de données en mémoire.
Ce que vous ne devriez jamais faire, c'est étendre la portée de votre transaction. Certaines personnes ont suggéré de prendre le contrôle de la transaction et de la annuler après les tests. Lorsque vous effectuez cette opération, toutes les entités (en supposant que vous utilisez JPA) restent attachées au contexte de persistance tout au long de l'exécution du test. Cela peut entraîner des bugs très désagréables qui sont très difficiles à trouver .
Au lieu de cela, vous devez effacer la base de données manuellement après chaque test via une bibliothèque comme JPAUnit ou similaire à cette approche (effacer toutes les tables à l'aide de JDBC).
En raison de vos problèmes de performances, vous ne devez pas exécuter les tests d'intégration sur chaque build. Laissez votre serveur d'intégration continue le faire. Si vous utilisez Maven, vous pouvez profiter du plug-in à sécurité intégrée qui vous permet de séparer vos tests en tests unitaires et d'intégration.
De plus, vous ne devriez rien vous moquer. N'oubliez pas que vous testez l'intégration, c'est-à-dire testez le comportement dans l'environnement d'exécution au moment de l'exécution.
la source
Sur l'évolutivité
J'ai eu ce problème quelques fois auparavant, que les tests d'intégration prenaient trop de temps à exécuter et n'étaient pas pratiques pour qu'un seul développeur s'exécute en continu dans une boucle de rétroaction étroite de modifications. Voici quelques stratégies pour y faire face:
Essayez de combiner ces techniques pour plus d'effet.
la source
À des fins de test, nous avons utilisé un déploiement basé sur fichier d'une base de données SQLite (il suffit de copier une ressource). Cela a été fait afin que nous puissions également tester les migrations de schéma. Pour autant que je sache, les modifications de schéma ne sont pas transactionnelles et ne seront donc pas annulées après l'abrogation d'une transaction. Le fait de ne pas avoir à compter sur la prise en charge des transactions pour la configuration du test permet de tester correctement le comportement des transactions de votre application.
la source