TDD avec SQL et fonctions de manipulation de données


14

Bien que je sois programmeur professionnel, je n'ai jamais été officiellement formé en génie logiciel. Comme je visite souvent ici et SO, j'ai remarqué une tendance à écrire des tests unitaires chaque fois que possible et, comme mon logiciel devient plus complexe et sophistiqué, je considère les tests automatisés comme une bonne idée pour faciliter le débogage.

Cependant, la plupart de mon travail consiste à écrire du SQL complexe puis à traiter la sortie d'une manière ou d'une autre. Comment écririez-vous un test pour vous assurer que votre SQL renvoie les données correctes, par exemple? Ensuite, si les données n'étaient pas sous votre contrôle (par exemple, celles d'un système tiers), comment pouvez-vous tester efficacement vos routines de traitement sans avoir à écrire à la main des rames de données factices?

La meilleure solution à laquelle je peux penser est de faire des vues des données qui, ensemble, couvrent la plupart des cas. Je peux ensuite joindre ces vues à mon SQL pour voir s'il renvoie les enregistrements corrects et traiter manuellement les vues pour voir si mes fonctions, etc. font ce qu'elles sont censées faire. Pourtant, cela semble excessif et floconneux; en particulier trouver des données pour tester contre ...


Réponses:


6

Une règle importante pour tester tout ce qui est lié à la base de données consiste à l'isoler complètement du reste de votre application.

L' architecture des ports et des adaptateurs est un très bon exemple. La base de données est considérée comme un plugin externe via un adaptateur à votre application. Il en va de même avec tous les sous-systèmes tiers. Pour tester le comportement de votre application et interpréter les réponses des sous-systèmes tiers, la seule façon dont je sais comment tester est de bloquer les réponses de ce sous-système individuel. Je ne veux pas nécessairement dire que vous devrez écrire manuellement tous les objets de données. Vous pouvez facilement adopter l'approche consistant à utiliser des tests basés sur les données.

En ce qui concerne le test de la façon dont votre application interagit avec votre base de données, vous pouvez simuler les adaptateurs de base de données pour utiliser une base de données en mémoire par exemple.

Testez maintenant vos requêtes de base de données. Tout d'abord, les requêtes complexes doivent être décomposées en requêtes plus faciles, simples et prévisibles. Comme vous le feriez pour une classe de graisse ou pour une fonction de graisse. Il existe des outils qui peuvent vous aider à tester votre base de données comme Dbunit. Une approche simple que je prends parfois consiste à utiliser le concept de tests de caractérisation. Je mettrais donc la base de données dans un état connu, exécuter toutes les requêtes que je dois écrire enregistrer la sortie dans un endroit (fichier, mémoire) et considérer cette sortie comme la bonne. Les prochaines exécutions compareraient leur sortie à celle-ci, ce qui m'offrirait certainement les tests de régression dont j'ai besoin. En effet, la première sortie n'est pas garantie d'être correcte mais le problème de régression peut être résolu de cette façon. Si vos requêtes sont bien décomposées, vous pouvez les tester individuellement vers la base de données qui est dans un état connu.


3

C'est une question intéressante car la base de données est généralement la partie truquée lors des tests unitaires d'application. Espérons que la logique du moteur de base de données lui-même est bien testée par le fournisseur, mais bien sûr, les requêtes, le schéma et les procédures stockées sont du code qui doit être testé et protégé contre la régression. Ceci est souvent laissé aux tests d'intégration qui ne sont pas TDD.

Les vues seraient probablement un moyen difficile de le faire car elles ne prêtent pas vraiment au test le premier test automatique au feu rouge et au feu vert d'un aspect par test qui est préféré dans TDD. De plus, avec les vues, vous ne pouvez pas écrire le test avant le code. Une meilleure approche serait d'écrire des procédures stockées dans lesquelles vous pouvez ajouter une logique "assert" dans la procédure (par exemple en utilisant des instructions "if") pour tester l'échec de la sortie. Vous devez tester une seule chose dans chaque test unitaire pour isoler l'unité, et la méthode SP serait mieux adaptée à cela. De plus, avec les SP, vous pouvez exécuter toute la suite d'entre eux sous forme de scripts pendant que vous développez le code initial et plus tard lors des tests de régression lors de la refactorisation.

Sachez également que les tests doivent être reproductibles et que vous aurez besoin de certains scripts pour initialiser et démonter l'état de la base de données pour vous assurer que l'état est le même pour chaque test unitaire.

Pour votre question sur les données qui ne sont pas sous votre contrôle, c'est un domaine difficile. Je pense qu'il vaut mieux s'en moquer avec de fausses données et tester autant que possible les conditions d'exception et de bord pour les tests unitaires. Sinon, il tombera davantage dans la catégorie des tests d'intégration (ce qui est également une bonne chose à faire). Pour les tests d'intégration, vous pouvez exécuter vos tests par rapport aux données tierces et les laisser générer une sortie initiale et pour les tests ultérieurs (par exemple après refactoring), assurez-vous que ces sorties répètent la sortie connue initiale.


Pourquoi ne pouvez-vous pas écrire un test pour une vue qui n'a pas encore été codée?
JeffO

Pas si vous utilisez la vue comme mécanisme pour le test comme l'OP l'a proposé.
Clé en main

1

À un moment donné, vous aurez besoin de données de test. Si vous utilisez un système tiers, le schéma a déjà été créé, mais vous devrez faire face aux modifications futures. J'espère que vous pourrez obtenir ces modifications dans la documentation de mise à niveau, mais vous serez peut-être obligé de comparer les versions de la base de données vous-même.

Les jeux de résultats attendus peuvent être enregistrés dans des tables de base de données ou des fichiers / feuilles de calcul externes. J'ai même vu CHECKSUM utilisé ou une comparaison. Lorsque vous testez une vue / sproc, vous obtiendrez un échec car ils n'existent pas. Ensuite, vous créez l'objet avec suffisamment de code pour au moins exécuter (SELECT -1 as [false_data];) et vous obtiendrez un échec car il ne correspond pas au jeu de résultats. Une fois qu'ils correspondent, vous avez votre feu vert.

J'ai commencé à travailler avec les propriétaires de projets et à leur demander de se moquer des rapports dans une feuille de calcul et d'essayer de produire des données partielles pour moi (vous pouvez mettre les données de résultat dans un tableau de test.). Il y a eu un peu de recul au début, mais ils ont réalisé que je vais créer un rapport et ils vont quand même devoir le vérifier. Cela a permis de gagner du temps à long terme. S'ils veulent faire une demande de modification, ils doivent refaire la feuille de calcul. Maintenant, ils peuvent répondre à la question: "À quel point serait-il difficile d'ajouter ...?"


1

Si votre plateforme de base de données est SQL Server, il existe un très bon outil gratuit: tSQLt .

tSQLt est un cadre de test d'unité de base de données pour Microsoft SQL Server. tSQLt est compatible avec SQL Server 2005 (service pack 2 requis) et supérieur sur toutes les éditions.

J'ai réussi à implémenter des tests au niveau de la base de données.

Certains des éléments clés qui le rendent si utile comprennent:

  • Capacité à travailler avec de fausses tables et vues, ce qui réduit la configuration normale impliquée
  • Les tests s'exécutent automatiquement dans les transactions (donc facilement réexécutables)
  • Vos assertions peuvent faire des comparaisons sur des tables (à la fois réelles et fausses) afin que vous puissiez voir si vous avez modifié facilement des données
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.