Un peu de contexte: plus tôt dans la journée, j'ai dû mettre à jour du code SQL fourni par un autre de mes collègues, et comme il s'agit d'un assez gros script, il est stocké dans un fichier séparé (qui est ensuite lu et exécuté au moment de l'exécution). En faisant cela, j'ai réintroduit accidentellement deux bugs que nous avions il y a quelques mois, à savoir:
SET
(requises en raison de certains problèmes de pilote en production, mais pas lors d'une nouvelle installation locale).Après avoir débogué cela pendant environ une heure (à nouveau), j'ai décidé d'écrire des tests unitaires pour m'assurer que cela ne se reproduirait plus jamais (et inclure un moyen rapide de le corriger dans le message d'assertion pour fournir une solution facile aux futurs développeurs).
Cependant, lorsque j'ai poussé ce code, un autre collègue (qui est également notre chef d'équipe) s'approche de moi et me dit que je ne devrais pas refaire ces choses parce que:
"Ces choses n'appartiennent pas aux tests unitaires"
"Les tests unitaires ne doivent être utilisés que pour vérifier le flux de votre code"
Je suis assez en conflit maintenant car je pense toujours que ce que je fais n'est pas mal, car ce bug ne serait pas réintroduit à l'avenir, mais ce collègue travaille comme senior et à la fin de la journée décide de ce que nous passons notre temps. Que devrais-je faire? Ai-je tort de le faire de cette façon? Est-ce considéré comme une mauvaise pratique?
Les tests que vous avez écrits sont très probablement plus proches des tests d'intégration ou de régression que des tests unitaires. Bien que la ligne puisse être très floue et se transforme parfois en pédanterie sur ce qui est ou n'est pas un test unitaire, je voudrais revenir à votre collègue et demander où les tests que vous avez écrits devraient être car ils ajoutent de la valeur garantissant l'exactitude du code.
Je ne me concentrerais pas trop sur ce qui est ou n'est pas un test unitaire et je me rendais compte que même s'il s'agit d'un test d'intégration, le test pourrait toujours avoir de la valeur.
Techniquement, il ne s'agit pas d'un test unitaire, mais plutôt d'une étape de validation. L'approche appropriée dépend vraiment de ce que votre flux de travail doit être. Votre chef d'équipe a raison sur l'objectif des tests unitaires. J'ai le sentiment qu'il s'agit d'utiliser le mauvais outil pour un travail qui doit encore être fait. Commencez donc par ceci:
Quel est le problème que j'essaie de résoudre?
Par la description, vous devez valider que tous les scripts de base de données sont conformes à certaines normes.
Quels outils/processus sont disponibles pour résoudre le problème?
La qualité du code source est généralement vérifiée par analyse statique outils. Si vous ne disposez pas d'un outil d'analyse statique pour valider votre SQL, vous pouvez créer un outil rapide et sale qui effectue la vérification tout fichier SQL transmis. Cela ne fait pas de mal de vérifier s'il existe des outils d'analyse statique qui peuvent gérer les problèmes dont vous parlez.
Si vous intégrez cette partie de votre infrastructure de génération, par exemple en l'incorporant à Jenkins ou quelque chose du genre, elle peut être appliquée à tous les fichiers SQL de votre projet.
Les tests unitaires ne résolvent que le problème de votre fichier actuel.
Comment communiquer le besoin de l'outil?
C'est assez facile, vous parlez à votre chef d'équipe. Il peut travailler avec le propriétaire du produit et vous pour déterminer le risque/récompense d'un investissement dans l'outillage. S'il s'agit probablement d'un problème ponctuel, l'outillage serait probablement exagéré. Si l'outillage pour attraper les plus gros problèmes est facile, cela peut en valoir la peine juste pour le contrôle de santé mentale.
Votre chef d'équipe peut avoir des idées que vous (ou moi) n'avons pas envisagées, qui peuvent résoudre le problème plus correctement.
Il n'est pas recommandé d'appeler les tests qui accèdent aux fichiers "Tests unitaires".
Lui: "Ces choses n'appartiennent pas aux tests unitaires"
Vous: "C'est logique, mais je n'ai pas pu trouver un meilleur endroit pour les mettre. Où appartiennent-ils?"
Malheureusement, quels types de tests existent et comment ils sont organisés est entièrement propre à l'entreprise. Vous devrez donc découvrir comment votre entreprise gère ces tests.
Si vous ne disposez pas encore d'un moyen d'exécuter des tests automatisés autres que les tests unitaires, l'approche pragmatique consiste à marquer les tests unitaires qui ne sont pas réellement des tests unitaires avec un préfixe, jusqu'à ce que vous en ayez assez pour commencer à déterminer quel type de tests que vous avez/avez réellement besoin. Après cela, vous pouvez commencer à organiser.
Michael Feathers dit ceci dans son livre Working Effectively With Legacy Code:
Dans l'industrie, les gens font souvent des va-et-vient pour savoir si des tests particuliers sont des tests unitaires. [...] Je reviens aux deux qualités: le test se déroule-t-il rapidement? Peut-il nous aider à localiser rapidement les erreurs?
Votre test aidera-t-il à localiser rapidement les erreurs et à s'exécuter rapidement? Si oui, alors faites-le! Si non, alors ne le faites pas! C'est aussi simple que ça!
Cela étant dit, vous travaillez dans un environnement avec d'autres personnes et devez vous entendre avec elles. Vous devrez peut-être finir par le faire à sa façon, même si vous n'êtes pas d'accord avec cela.
J'ai parfois écrit des tests similaires sur des fichiers de code source, des fichiers de configuration, etc. Je ne les appellerais pas des tests unitaires car (a) ils accèdent au système de fichiers et ne sont peut-être pas ultra-rapides (b) je m'en fiche s'ils sont exécutés à chaque enregistrement (par opposition à tous les soirs sur un Serveur CI).
Vous pourriez les appeler des tests d'intégration; ils sont certainement plus proches de cette perspective que les tests unitaires.
Mon propre terme pour eux est tests de ressources. À mon humble avis, ils sont entièrement justifiés s'ils sont exécutés la nuit sur un serveur CI: leur coût est minime et, lorsqu'ils sont utilisés judicieusement, ils ajoutent clairement de la valeur. Une définition de judicieusement: si le test vérifie un problème qui a causé un problème (comme l'encodage que vous mentionnez).
Un test unitaire consiste à tester une méthode ou une "unité" de code. Vous testez le plus petit groupe de logique et de code de votre logiciel.
Plus tard, lorsque vous le joindrez à d'autres unités, vous effectuerez des tests d'intégration.
J'espère que votre chef d'équipe a encouragé votre initiative et aurait dû proposer des suggestions alternatives. Vous avez définitivement la bonne idée.
Votre SQL est du code comme tout langage de génération inférieure comme C # ou Java et doit être testé en tant que tel. Et la vérification et la validation appartiennent à tous les niveaux de test. Ainsi, les instructions d'encodage et SET sont incluses, mais pas nécessairement testé exclusivement. Des trucs généraux comme les fins de ligne ou la clôture, vous pouvez généralement simplement utiliser un crochet ou une fonction SCM.
La meilleure pratique consiste à avoir des tests de régression pour s'assurer que les bogues passés ne sont pas réintroduits. Généralement, les tests sont créés à côté de toute résolution du bogue. Si ces bogues ne sont pas couverts par des tests de régression au niveau de l'unité/intégration ou du système, puis réintroduits, c'est un problème d'équipe, un problème de processus, pas un problème individuel.
Le truc c'est que ... les erreurs de syntaxe, les instructions manquantes ou les blocs logiques à l'intérieur d'une "unité" ne sont généralement pas testés. Vous testez les entrées et sorties de l'unité dans différentes combinaisons, testant les nombreuses possibilités qui pourraient être générées.
Revenir aux instructions SET manquantes - elles aident à informer les nombreuses possibilités d'entrée et de sortie à tester. Quel test écririez-vous qui échouerait si vous manquiez un ensemble choisi?
Si vous avez des fichiers qui font partie de votre produit, leur contenu doit être correct. Aucune raison pour laquelle vous ne vérifieriez pas cela. Par exemple, si vous avez besoin de six images 1024x 1024 dans un dossier, écrivez certainement un test unitaire qui vérifie que vous avez exactement cela.
Mais vous n'avez probablement pas seulement les fichiers, vous avez également du code qui lit les fichiers. Vous pouvez écrire un test unitaire pour ce code. Dans l'exemple ci-dessus, la fonction de lecture d'une des six images renvoie-t-elle une image 1024 x 1024 en mémoire (ou tout ce qu'elle était censée produire).
Quoi qu'il en soit, ce n'est peut-être pas un test unitaire, mais c'est un test utile. Et si vous utilisez un framework de test unitaire qui vous permet de faire un test utile (qui n'est pas un test unitaire), pourquoi ne pas utiliser le framework de test unitaire?
Peut-être que je comprends mal votre problème, mais pour moi, cela ressemble à un problème qui ne devrait pas avoir besoin d'être capturé par une sorte de test dédié, mais simplement par le système de contrôle de version. Toute modification apportée à une base de code doit être examinée patch par patch avant de valider. Un moyen simple de le faire dans git est d'ajouter les modifications avec
git add -p
Cela pour chaque changement dans un fichier texte, le répertoire de travail vous demandera si vous voulez vraiment le conserver. Cela vous permettrait de voir, par exemple, la suppression de ces "instructions initiales SET
".
Dans le cas où l'encodage d'un fichier entier changerait, quelque chose de différent se produirait cependant: l'algorithme ne parviendrait pas à différencier l'ancien et le nouveau fichier, et donc git add -p
N'ajouterait rien du tout. Ce serait alors visible dans l'autre commande que je ferais avant tout commit, à savoir
git status
Ici, vous verrez le fichier surligné en rouge, indiquant qu'il y a sont changements. La recherche de la raison pour laquelle ceux-ci ne se sont pas transformés en git add -p
Rendrait rapidement le problème évident.
Un autre angle à considérer: puisque ces deux conditions sont des exigences pour que votre programme s'exécute, ne devriez-vous pas incorporer la logique près de la logique d'exécution? Je veux dire: vous testez l'existence d'un fichier avant de le lire et/ou validez son contenu, non? alors comment est-ce différent? Je pense que puisqu'il s'agit d'une ressource externe au code, elle doit être validée au moment de l'exécution, avant d'être réellement utilisée. Résultat: application plus puissante, pas besoin d'écrire des tests supplémentaires.
Les tests unitaires consistent à exécuter une unité de code de manière isolée pour confirmer qu'elle produit le bon résultat pour la bonne entrée. L'isolement doit rendre à la fois l'unité testée et le test lui-même reproductibles, c'est-à-dire ne pas dépendre ni introduire d'effets secondaires.
SQL n'est pas exactement quelque chose qui peut être testé isolément, donc tout test de SQL n'est pas exactement un test unitaire et, à l'exception des instructions SELECT, il est presque certain d'avoir un effet secondaire. Nous pouvons l'appeler un test d'intégration plutôt qu'un test unitaire.
Il est toujours sage de s'assurer que tout défaut qui pourrait être introduit peut être détecté le plus tôt possible dans le cycle de développement, et il est avantageux de le faire d'une manière qui facilite l'identification de la source du défaut afin qu'il puisse être rapidement détecté. corrigée.
Les tests en question peuvent être déplacés de manière plus appropriée hors du corps des "tests unitaires" et placés ailleurs, mais ne devraient pas être supprimés complètement s'ils font quelque chose d'utile comme se prémunir contre l'introduction éventuelle d'un défaut qui pourrait prendre des heures à suivre vers le bas.
Les tests sont le même code que les autres et, s'ils sont suffisamment complexes, bénéficient également de ... tests unitaires. Il semble plus simple d'ajouter de telles vérifications de précondition directement dans le test.
La plupart des tests sont assez simples pour ne pas l'exiger, mais si certains sont suffisamment complexes, je ne vois rien de fondamentalement mauvais avec ces vérifications de condition préalable. Bien sûr, le test devrait également échouer sans eux, mais un bon test unitaire indique également quelle unité échoue.
Un script utilisé dans le cadre du test et qui doit avoir un certain contenu et un certain codage est probablement une unité. Il peut avoir beaucoup plus de code et de logique que le reste du test. Un test avec un tel script n'est pas le meilleur design jamais conçu et, si possible, devrait être refactorisé en quelque chose de plus direct (sauf s'il s'agit d'un test d'intégration).
Premièrement - l'un des objectifs des tests est d'empêcher que des problèmes ne se reproduisent dans votre code - donc vous devez absolument continuer à écrire des tests de cette nature.
Deuxièmement - la dénomination est difficile. Oui, ce ne sont clairement pas des "tests unitaires", mais ils peuvent être des éléments souhaitables et nécessaires du processus de construction, car ils vous protègent contre les erreurs évidentes et parce qu'ils vous donnent un retour sur les erreurs plus tôt (surtout étant donné que vous ne voyez pas le conséquences sur une boîte de développement).
Donc, la question est vraiment (devrait être dans votre contexte) plus de savoir quand et comment ces tests sont exécutés que ce qu'ils sont.
J'ai utilisé ce genre de test dans le passé - ils nous ont sauvé une bonne partie de la douleur.