2010-05-31 8 views
3

J'ai un problème extrêmement étrange dans mes tests JUnit que je n'arrive pas à résoudre. J'ai un projet webapp java multi-module avec une structure assez standard (DAO, service clasess, etc ...). Dans ce projet, j'ai un projet «noyau» qui contient un code de configuration abrégé qui insère un utilisateur de test avec les éléments nécessaires pour un utilisateur (dans ce cas une «entreprise», donc un utilisateur doit appartenir à une entreprise et ceci est appliqué au niveau de la base de données)Le test JUnit échoue - se plaindre des données manquantes qui viennent d'être insérées

assez simple jusqu'à présent ... mais voici où l'étrangeté commence

  1. certains tests ne parviennent pas à courir et lancer une exception de base de données où il se plaint que ne peut pas être inséré un utilisateur, car un l'entreprise n'existe pas. Mais il a juste créé l'entreprise dans la ligne de code précédente! Et il n'y avait pas d'erreurs dans l'insertion de l'entreprise.
  2. Encore plus étrange, si cette classe de test est exécutée par elle-même, tout fonctionne correctement. Ce n'est que lorsque le test est exécuté dans le cadre du projet qu'il échoue!
  3. Et le même code abstrait a été exécuté par plus de 10 tests avant celui qui échoue!
  4. f

Je suis frappais la tête contre un mur avec ce pendant plusieurs jours et n'ont pas vraiment fait des progrès. Je ne suis même pas sûr de ce que l'information à offrir pour aider à diagnostiquer cela.

  • JUnit 4.4, Spring 2.5.6, 2.3.0 iBatis, Postgresql 8.3
  • Passage à org.springframework.jdbc.datasource.DriverManagerDataSource de org.apache.commons.dbcp.BasicDataSource changé le problème. Avec DriverManagerDataSource, les tests fonctionnent pour la première fois, mais maintenant tout à coup, beaucoup de données ne sont pas restaurées dans la base de données! Ça laisse tout derrière. Tous sans erreur
  • Les tests échouent lorsqu'il est exécuté via Eclipse & Maven

S'il vous plaît demander toute information qui peut me aider à résoudre mon problème!

Mise à jour: J'ai augmenté la journalisation au maximum. Il y a seulement une petite différence entre ce test qui échoue, et un autre juste comme ça qui réussit. La différence est mise en évidence. Après l'erreur se produit, je vois un certain nombre de « Création [java.util.concurrent.ConcurrentHashMap] » lignes et le code de gestion des erreurs commence

+0

Pouvez-vous inspecter la base de données au moment de l'échec? A-t-il réellement le dossier d'entreprise? – Yishai

+0

pouvez-vous donner s'il vous plaît fournir votre modèle db .. – bragboy

Répondre

0

Eh bien ... il me semble avoir trébuché sur la solution à ce problème, même si je ne peux pas vraiment mettre le doigt sur ce qu'il est exactement. Je reconstruisais mes tests en les déplaçant tous et ensuite en les restaurant un par un. Faible et ce n'est qu'après avoir ajouté la classe de test finale que le problème a réapparu

Cette classe de test étendue à partir d'une classe de test de base qui définissait toutes les annotations de configuration liées à Spring comme @RunWith et @ContextConfiguration. Pour une raison quelconque, cette classe de test a redéfini les attributs @RunWith et @ContextConfiguration et dès que je les ai supprimés, les choses ont recommencé. L'autre chose étrange à propos de cette classe de test était que j'utilisais @Ignore sur chaque test (il contenait quelques vieux tests).

Alors ... si quelqu'un a jamais cet étrange problème, vous pouvez essayer de supprimer les annotations supplémentaires pour le corriger

1

Ceci est un disque problème à résoudre sur SO, mais je vais faire une supposition sauvage sur la base des détails que vous avez donnés. Hypothèse: Les insertions dans le test se produisent toutes dans une transaction, qui est annulée. (C'est pourquoi BasicDataSource laisse la base de données propre - elle revient à la fin). Lorsque cela s'arrête (en utilisant DriverManagerDataSource), le test réussit mais la base de données n'est pas annulée. Cela suggère que, même si "il vient de créer l'entreprise dans la ligne de code précédente!" la transaction peut être annulée pour supprimer l'enregistrement.D'autres hypothèses (ok que sur les états, essayez sauvage), quelque chose (soit dans BasicDataSource ou plus probablement votre propre code d'infrastructure) appelle l'annulation de la transaction dans un finaliseur. C'est pourquoi il fonctionne 10 fois et plus, puis échoue, et seulement dans le cadre du projet - c'est cette exécution qui déclenche la récupération de place à ce moment, provoquant l'annulation de la transaction, provoquant le lancement d'une nouvelle transaction avec les enregistrements dans un état invalide.

EDIT: A partir de votre édition, il semble que, pour une raison quelconque le test d'échec, vous obtenez une nouvelle connexion de base de données. Cela correspond à mon scénario ci-dessus, mais pourrait également être expliqué en déclarant que pour une raison quelconque, à ce moment-là dans le code obtient une nouvelle transaction lorsque le test est exécuté dans le cadre de l'ensemble du projet. La nouvelle transaction ne voit pas l'insertion de l'enregistrement d'entreprise qui se produit dans une transaction différente et la transaction reste ouverte et non validée. Une façon de tester cela est de définir le niveau d'isolation de la transaction sur cette course au maximum, de sorte que rien ne puisse balayer la table de l'entreprise tant qu'il y a une transaction dessus. Ensuite, votre code serait bloqué si ce scénario est correct.

plus EDIT: Ce que je veux dire par un finaliseur qui appelle est proche quelque chose comme ceci:

public class SomeConnectionWrapper { 
     private Connection dbConnection; 

     protected void finalize() { 
      dbConnection.close(); 
     } 
} 

Si SomeConnectionWrapper est détruite et la connexion fermée, votre pool de connexion de base de données renvoie une autre connexion.

+0

Merci pour l'aide Yishai. Comment serait-il possible qu'une transaction soit annulée sans que rien ne déclenche cette annulation? c'est-à-dire qu'il n'y a pas d'erreur du tout et je ne déclenche pas de retour en arrière. Je viens de Amped l'exploitation forestière au maximum et il n'y a qu'une seule différence que je vois entre ce test qui échoue et une autre comme elle. Je vais publier ces résultats dans une minute –

+0

@Collin, comme je l'ai dit, je suis dans le territoire sauvage. Une restauration peut être déclenchée dans le code de plusieurs manières: Fermeture d'une connexion de base de données définie sur 'autocommit: false' ou annulation explicite. Je vérifierais votre code pour un finaliseur qui ferme la connexion. – Yishai

+0

Résultats affichés dans la question principale –

1

je suis tombé sur un problème similaire en utilisant junit4 et au printemps. J'ai dû ajouter @Transactional à mes méthodes de test afin de relire des choses de la base de données avant une validation.