Test unitaire des procédures stockées


44

J'y réfléchis depuis assez longtemps.

La question de base est la suivante: comment tester à l'unité les procédures stockées?

Je vois que je peux mettre en place des tests unitaires relativement facilement pour des fonctions au sens classique (je veux dire qu'ils ne reçoivent aucun argument ou plus et renvoient une valeur). Mais si je considère un exemple réel d'une procédure apparemment simple insérant une ligne quelque part, avec quelques déclencheurs faisant cela et qu'avant ou après l'insertion, même définir les limites d'une «unité» est assez difficile. Devrais-je tester seulement le INSERTlui-même? Je pense que c'est assez simple - avec une valeur relativement faible. Devrais-je tester le résultat de toute la chaîne d'événements? Indépendamment de la question de savoir s’il s’agit d’un test unitaire ou non, concevoir un test approprié peut s’avérer très laborieux et susciter de nombreuses interrogations supplémentaires.

Vient ensuite le problème de l’évolution constante des données. Dans le cas d'une UPDATEincidence affectant plus que quelques lignes, chaque ligne potentiellement affectée doit être incluse d'une manière ou d'une autre dans les cas de test. Autres difficultés avec DELETEs et ainsi de suite.

Alors, comment testez-vous vos procédures stockées? Y a-t-il un seuil dans la complexité où il devient complètement sans espoir? Quelles ressources sont nécessaires pour la maintenance?

EDIT Une dernière petite question, basée sur la réponse d'Alex Kouznetsov: Ou y a-t-il un seuil en dessous duquel il est complètement inutile?

Réponses:


32

Nous le faisons depuis près de cinq ans et nous pensons que tester explicitement les modifications est tout à fait faisable, mais c'est assez lent. En outre, nous ne pouvons pas facilement exécuter simultanément de tels tests à partir de plusieurs connexions, à moins d'utiliser des bases de données distinctes. Au lieu de cela, nous devrions tester les modifications implicitement - nous les utilisons pour construire au moins certaines des données de test et nous vérifions que notre sélection renvoie les résultats attendus.

J'ai écrit un article intitulé Fermer ces échappatoires: Leçons tirées du test unitaire de T-SQL , ainsi que certains articles de blog

En ce qui concerne votre question "Y a-t-il un seuil de complexité qui rend tout désespéré?", Les modules complexes nécessitent des tests bien plus que de simples.

Pour simplifier la maintenance, nous générons les résultats attendus et nous les stockons dans des fichiers séparés, ce qui fait toute la différence.


15

Oui, vous devriez tester toute la chaîne d'événements en tant qu'unité. Ainsi, dans votre exemple avec une procédure qui s'insère dans une table et provoque l'activation de plusieurs déclencheurs, vous devez écrire des tests unitaires qui évaluent la procédure pour différentes entrées. Chaque test unitaire doit réussir ou échouer selon qu'il renvoie ou non les valeurs correctes, modifie correctement l'état des tables, crée le courrier électronique correct et envoie même les paquets réseau corrects s'il est conçu pour le faire. En bref, chaque effet de l’appareil doit être vérifié.

Vous avez raison de dire que la conception des tests unitaires demande du travail, mais que la majeure partie de ce travail doit être effectuée pour tester manuellement l'unité. Vous ne faites que sauvegarder le travail nécessaire pour tester l'unité. peut être tout aussi complet et beaucoup plus facile.

Changer les données rend les tests plus difficiles, mais cela ne les rend pas moins importants et augmente réellement la valeur des tests unitaires, car la plupart des difficultés ne doivent être réfléchies qu’une seule fois, et non à chaque changement apporté à l’unité. Des ensembles de données enregistrés, des insertions / mises à jour / suppressions faisant partie de la configuration / du démontage et une opération à portée étroite peuvent tous être utilisés pour faciliter cette opération. Comme la question n'est pas spécifique à la base de données, les détails varieront.

Aucun seuil de complexité, haut ou bas, ne devrait vous empêcher d'effectuer des tests ou des tests unitaires. Considérez ces questions:

  1. Est-ce que vous écrivez toujours du code sans bug?
  2. Les petites unités sont-elles toujours exemptes de bogues?
  3. Est-ce correct pour une grosse unité d'avoir un bug?
  4. Combien de bugs faut-il pour provoquer une catastrophe?

Supposons que vous commenciez un nouveau travail et que vous soyez chargé de l’optimisation d’une petite fonction utilisée à de nombreux endroits. La totalité de l'application a été écrite et gérée par un employé dont personne ne se souvient même. Les unités ont une documentation décrivant le comportement attendu normal, mais guère plus. Lequel de ceux-ci préféreriez-vous trouver?

  • Aucun test unitaire n’importe où dans l’application. Une fois la modification effectuée, vous pouvez effectuer des tests manuels sur l'unité afin de vous assurer qu'elle renvoie toujours les valeurs attendues dans la documentation. Vous pouvez ensuite passer à la production, croiser les doigts et espérer que cela fonctionne (après tout, vous écrivez toujours du code sans bogues et une optimisation dans une unité ne peut en affecter une autre) ou passez énormément de temps à apprendre comment toute l'application fonctionne de sorte que vous pouvez tester manuellement chaque unité effectuée directement ou indirectement.
  • Tests unitaires dans l'application qui s'exécutent automatiquement quotidiennement ou à la demande Ils vérifient non seulement les valeurs d'entrée normales et leur réponse attendue, mais également les valeurs anormales et les exceptions attendues qui sont déclenchées. Vous effectuez votre modification et exécutez immédiatement la suite de tests d'unités pour l'application en sachant que trois autres unités ne renvoient plus les résultats attendus. Deux d'entre eux sont bénins, vous devez donc ajuster les tests unitaires pour en tenir compte. La troisième nécessite un autre léger ajustement et un nouveau petit test unitaire. Une fois les modifications apportées, l'ensemble de la suite de tests réussit et vous les déployez en toute confiance.

1
Tout d'abord, merci pour votre réponse - je ne m'attendais pas à plus d'avancée sur cette question ... Deuxièmement, je dois admettre que vous avez raison à propos des opérations simples: même un INSERT à deux colonnes peut générer un bogue. S'il est écrit de manière à ce que l'ordre des colonnes puisse être mis en correspondance avec les arguments, alors tout ira bien, mais vous avez raison, encore une fois: il est probablement préférable de garder l'ensemble de l'application sous le régime de test.
Dezso

@dezso C'est une excellente question et un concept qui nécessite beaucoup plus de visibilité dans le monde des bases de données.
Leigh Riffel

"vous devriez tester toute la chaîne d'événements comme une unité" - c'est la chose la plus contre-intuitive que vous puissiez dire. Ce n'est pas une unité si c'est le cas. Vous faites des tests d'intégration
Joe Phillips

@ Joe Philips - Appelez cela comme vous voulez, en vous assurant qu'une procédure qui insère et déclenche quelques déclencheurs fait ce qu'elle est supposée nécessiter pour des tests automatisés.
Leigh Riffel

8

Pour PostgreSQL, consultez pgTAP :

pgTAP est une suite de fonctions de base de données qui facilite l'écriture de tests unitaires émetteurs de TAP dans des scripts psql ou des fonctions de test de type xUnit.


Vu ça, merci. Est-ce que quelqu'un a de l'expérience avec elle?
dezso

Oui, pas mal de monde aujourd'hui. Abonnez-vous à la liste de diffusion si vous avez des questions.
théorie

6

Si vous préférez que vos tests des procédures stockées soient entièrement réalisés sur SQL, consultez http://tsqlt.org/

Il est compatible avec MS SQL 2005 SP2 et les versions ultérieures, ce qui présente l'avantage que les développeurs n'ont pas besoin de connaître C # ou un autre langage pour implémenter les tests.

Il existe également des installations permettant de simuler des tables et des vues pour vous aider à réaliser une suite de tests ré-exécutable.

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.