Au travail, l'un de mes projets consiste principalement à prendre des données transmises par un client externe et à les conserver dans une base de données. Il s'agit d'une application d'entreprise Java utilisant JPA et la plupart de nos logiques tournent autour des opérations CRUD.
La majorité de nos bogues impliquent JPA d'une manière ou d'une autre.
- Exemple 1: Si vous cliquez deux fois sur le bouton Enregistrer, JPA peut essayer d'insérer la même entité dans la base de données une deuxième fois, provoquant une violation de clé primaire.
- Exemple 2: vous récupérez une entité de la base de données, la modifiez et essayez de mettre à jour ses données. JPA peut essayer de créer une nouvelle instance au lieu de mettre à jour l'ancienne.
Souvent, la solution doit ajouter / supprimer / modifier une annotation JPA. D'autres fois, il s'agit de modifier la logique DAO.
Je ne peux pas comprendre comment obtenir la confiance dans notre code en utilisant des tests unitaires et TDD. Je ne sais pas si c'est parce que les tests unitaires et TDD sont mal adaptés, ou si j'approche mal le problème.
Les tests unitaires semblent être un mauvais ajustement car je ne peux découvrir ces problèmes qu'au moment de l'exécution et je dois déployer sur un serveur d'applications pour reproduire les problèmes. Habituellement, la base de données doit être impliquée, ce que je considère être en dehors de la définition d'un test unitaire: ce sont des tests d'intégration.
TDD semble être un mauvais ajustement car la boucle de rétroaction de déploiement + test est si lente qu'elle me rend très improductif. La boucle de rétroaction de déploiement + test prend plus de 3 minutes, et c'est juste si j'exécute les tests spécifiquement sur le code que j'écris. Pour exécuter tous les tests d'intégration prend plus de 30 minutes.
Il y a du code en dehors de ce moule et je teste toujours cela chaque fois que je le peux. Mais la majorité de nos bogues et les plus gros puits de temps impliquent toujours JPA ou la base de données.
Il y a une autre question qui est similaire , mais si je suivais les conseils, j'envelopperais la partie la plus instable de mon code (le JPA) et testerais tout sauf lui. Dans le cadre de ma question, je serais dans la même mauvaise situation. Quelle est la prochaine étape après avoir enveloppé l'APP? OMI, cette question est (peut-être) une étape pour répondre à ma question, mais pas une réponse.
la source
unit testing != TDD
)Réponses:
Une option consiste à utiliser une base de données de test en mémoire telle que H2 ; il a tendance à être environ 10 fois plus rapide qu'une base de données utilisant un disque standard, et avec des temps de démarrage / démontage inférieurs.
Que cela aide ou non dépend en grande partie du fait que les problèmes JPA que vous rencontrez sont suffisamment généraux pour qu'ils échouent toujours sur différentes bases de données. Pas beaucoup de tests en cours d'exécution plus rapides s'ils ratent la majeure partie des problèmes.
Mais si vous pouvez faire 10 courses avec H2 pour chacun avec le système complet, cela pourrait être payant.
la source
Les bases de données peuvent être très faciles à tester unitairement - vous avez besoin de procédures et de transactions stockées.
Voici ce que dit Microsoft à propos des tests unitaires de base de données . Vous pouvez également exécuter des tests unitaires sur une base de données, écrire vos tests en Java ou en C # en configurant une connexion DB, en commençant une transaction, en écrivant toutes les données que vous souhaitez utiliser pour le test dans la base de données, en exécutant les tests et en les annulant. Aucun dommage à la base de données si vous en utilisiez une que vous avez également déployée et que vous obtenez des tests entièrement isolés.
J'espère que cela peut vous donner un aperçu de la façon de le faire dans votre cadre.
la source
D'autres personnes ont répondu "Mock out your DB!" - mais quel est l'intérêt de se moquer de votre couche DB si vous avez réellement besoin de tester comment il interagit avec votre code?
Ce que vous recherchez, ce sont des tests d'intégration et / ou des tests d'interface utilisateur automatisés. Vous avez mentionné que le problème se produit lorsque:
La seule façon de tester cela est d'écrire un test d'interface utilisateur automatisé pour cliquer deux fois sur le bouton. Peut-être consultez le sélénium.
Vous aurez probablement aussi besoin d'une base de données de tests unitaires et pour vos tests, dirigez-la vers cela. Une douleur à maintenir mais bienvenue au TDD dans le monde réel.
la source
Dans l'exemple que vous donnez dans votre question, vous ne pouvez pas effectuer de test unitaire / TDD dans la situation de cliquer deux fois sur le bouton pour provoquer une erreur très facilement. Mais ce que vous pouvez tester unitairement, c'est que dans le code qui est appelé lorsque vous cliquez sur le bouton, si vous obtenez une exception de la couche de persistance, vous la gérez de manière appropriée (soit en simulant la couche de persistance, soit en utilisant une base de données en mémoire comme a été suggéré dans d'autres réponses) - soit en relançant ou en affichant une erreur ou autre chose.
Vous avez raison de dire que TDD peut commencer à tomber en panne lorsque vous devez effectuer des tests qui ne conviennent pas à un test unitaire (c.-à-d. Tests d'intégration / système) - cela a constitué une grande partie de la discussion dans le récent "Is TDD Mort?" débats entre Kent Beck, Martin Fowler et David Heinemeier Hansson: http://martinfowler.com/articles/is-tdd-dead/
la source