Question

Je travaille sur un projet Spring MVC et j'ai des tests unitaires pour tous les divers composants de l'arbre source.

Par exemple, si j’ai un contrôleur HomeController , qui doit recevoir un LoginService , puis dans mon test unitaire HomeControllerTest J'instancie simplement l'objet normalement (en dehors de Spring) et injecte la propriété:

protected void setUp() throws Exception {
    super.setUp();
    //...
    controller = new HomeController();
    controller.setLoginService( new SimpleLoginService() );
    //...
}

Cela fonctionne très bien pour tester chaque composant en tant qu’unité isolée - à part maintenant que j’ai quelques dizaines de classes dans le projet, après avoir écrit une classe et rédigé un test unitaire réussi, j’oublie de mettre à jour mon contexte Spring MVC. fichier qui effectue le câblage dans l'application déployée. Je découvre que j'ai oublié de mettre à jour le fichier de contexte lorsque je déploie le projet sur Tomcat et que je trouve un tas de NullPointers à partir de beans non câblés.

Alors, voici mes questions:

  1. Ceci est mon premier projet Spring - est-il normal de créer des tests unitaires pour les beans individuels, comme je l'ai fait, puis de créer une deuxième suite de tests (tests d'intégration) pour vérifier que tout fonctionne comme prévu le contexte d'application réel? Existe-t-il une meilleure pratique établie pour cela?

  2. De plus, comment séparer les tests unitaires des tests d'intégration? J'ai tout le code source dans src , les tests unitaires dans test - devrait-il exister un deuxième dossier de test (tel que test-integration ) pour les cas de test d'intégration?

Comme il s’agit de mon premier projet Printemps, je suis curieux de voir comment les autres s’y prennent - et plutôt que de réinventer la roue, je le demande plutôt au reste de la communauté.

Était-ce utile?

La solution

Je ne peux pas parler de pratique exemplaire, mais voici ce que j'ai fait par le passé.

Tests unitaires:

  • Créez des tests unitaires pour des haricots non triviaux (c.-à-d. la plupart de vos haricots liés à Spring)
  • Utilisez des maquettes pour services injectés lorsque cela est pratique (c'est-à-dire presque tout le temps).
  • Utilisez une convention de dénomination standard pour ces tests dans le répertoire du projet test . L'utilisation de Test ou TestCase comme préfixe ou suffixe du nom de la classe semble être une pratique courante.

Tests d'intégration:

  • Créez un AbstractIntegrationTestCase qui configure un Spring WebApplicationContext à utiliser dans des classes de test d'intégration.
  • Utilisez une convention de dénomination pour les tests d'intégration dans le répertoire test . J'ai utilisé IntTest ou IntegrationTest comme préfixe ou suffixe pour ces tests.

Configurez trois cibles de test :

  1. test-all (ou le nom de votre choix): Exécuter des tests d'unité et d'intégration
  2. test: exécuter des tests unitaires (simplement parce que test semble être l'utilisation la plus courante pour les tests unitaires
  3. test-integration: lancez les tests d'intégration.

Comme indiqué, vous pouvez utiliser les conventions de dénomination appropriées pour votre projet.

Pour ce qui est de séparer les tests unitaires des tests d'intégration dans un répertoire séparé, je ne pense pas que cela soit important tant que les développeurs et leurs outils peuvent les trouver et les exécuter facilement.

À titre d'exemple, le dernier projet Java sur lequel j'ai travaillé avec Spring utilisait exactement ce qui est décrit ci-dessus, avec des tests d'intégration et des tests unitaires résidant dans le même répertoire test . Les projets Grails, en revanche, séparent explicitement les répertoires de test d’unités et d’intégration dans un répertoire de test général.

Autres conseils

Quelques points isolés:

Oui, il s’agit d’une approche courante des tests Spring: des tests unitaires distincts et des tests d’intégration dans lesquels les tests précédents ne chargent aucun contexte Spring.

Pour vos tests unitaires, envisagez peut-être de vous moquer pour vous assurer que vos tests sont concentrés sur un module isolé.

Si vos tests génèrent une multitude de dépendances, ils ne sont pas vraiment des tests unitaires. Ce sont des tests d'intégration dans lesquels vous câblez des dépendances en utilisant une nouvelle injection plutôt qu'une injection de dépendance. Une perte de temps et des efforts redondants lorsque votre application de production utilise Spring!

Les tests d'intégration de base pour faire apparaître vos contextes Spring sont utiles.

L'annotation @ requis peut vous aider à saisir les dépendances requises dans votre câblage Spring.

Peut-être cherchez-vous dans Maven qui vous donnera des phases explicites pour lier votre unité et vos tests d’intégration. Maven est assez largement utilisé dans la communauté de Spring.

Une partie de la double comptabilité fastidieuse avec le printemps disparaît si vous passez également à un régime purement annoté, dans lequel vous annotez tous vos beans avec @Component, @Controller, @Service et @Repository. Ajoutez simplement @Autowired aux attributs nécessaires à l’injection.

Voir section 3.11 du manuel de référence des ressorts. http: //static.springframework. org / spring / docs / 2.5.x / reference / beans.html # beans-annotation-config

Sur une note connexe, nous avons utilisé les tests de division / intégration de la division décrits par KenG. Dans mon dernier régime, nous avons également introduit un troisième "classe". des tests, "ComponentTests". Celles-ci fonctionnent avec un câblage à ressort complet, mais avec des implémentations de tronçon câblé (à l'aide de filtres d'analyse de composant et d'annotations au printemps).

La raison pour laquelle nous avons fait cela est que, pour certains "& service; service" " couche vous vous retrouvez avec une quantité horrible de logique de câblage codée à la main pour câbler manuellement le haricot, et parfois une quantité ridicule de faux-objets. 100 lignes de câblage pour 5 lignes de test n'est pas rare. Les tests de composants permettent de résoudre ce problème.

Utilisez l'interface InitializingBean (implémente une méthode "afterPropertiesSet") ou spécifiez une méthode init pour vos beans. InitializingBean est généralement plus facile car vous n'avez pas besoin d'ajouter la méthode init à vos beans.

Utilisez afterPropertiesSet pour vous assurer que tout est injecté de manière non nulle. S'il est nul, générez une exception.

Lorsque j'ai créé les tests d'intégration pour les applications Web, je les ai placés dans un répertoire séparé. Ils sont construits à l'aide de jUnit ou TestNG et interagissent avec le système testé en utilisant quelque chose comme Selenium , qui s'affiche sur les pages Web. comme s'ils étaient des utilisateurs. Le cycle ressemblerait à ceci: compiler, exécuter des tests unitaires, créer l'application Web, la déployer sur un serveur en cours d'exécution, exécuter les tests, annuler le déploiement de l'application et générer des résultats de rapport. L'idée est de tester l'ensemble du système.

En ce qui concerne l’exécution de tests unitaires séparément des tests d’intégration, j’ai mis tous ces derniers dans un répertoire d’intégration-test et les ai exécutés à l’aide de IDE / Ant selon une approche telle que this . Ça marche pour moi.

La différence entre le test unitaire et le test d’intégration est qu’un test unitaire ne charge pas nécessairement votre contexte, vous vous concentrez sur le code que vous avez écrit. en elle. Mais dans le cas de tests d’intégration, vous chargez le contexte et effectuez un test de bout en bout comme des scénarios réels.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top