Je suis un développeur de logiciel relativement nouveau, et l'une des choses que je pense devoir améliorer est ma capacité à tester mon propre code. Chaque fois que je développe une nouvelle fonctionnalité, il m'est vraiment difficile de suivre tous les chemins possibles pour trouver des bogues. J'ai tendance à suivre le chemin où tout fonctionne. Je sais que c'est un problème bien connu des programmeurs, mais nous n'avons pas de testeurs chez mon employeur actuel et mes collègues semblent être plutôt bons dans ce domaine.
Dans mon entreprise, nous ne faisons ni développement piloté par les tests, ni tests unitaires. Cela m'aiderait beaucoup mais il est peu probable que cela change.
Que pensez-vous que je pourrais faire pour surmonter cela? Quelle approche utilisez-vous pour tester votre propre code?
Réponses:
Le travail d'un codeur est de construire des choses.
Le travail d'un testeur est de casser des choses.
Le plus difficile est de casser des choses que vous venez de construire. Vous ne réussirez qu'en franchissant cette barrière psychologique.
la source
Franciso, je vais faire quelques hypothèses ici, sur la base de ce que vous avez dit:
"Nous ne faisons pas de tests TDD ni de tests unitaires. Cela m'aiderait beaucoup, mais il est peu probable que cela change."
À partir de là, j’imagine que votre équipe n’accorde pas beaucoup d’importance aux tests et que la direction ne lui accordera pas de temps pour essayer de ranger le code existant et de réduire au minimum sa dette technique .
Premièrement, vous devez convaincre votre équipe / direction de la valeur des tests. Soyez diplomate. Si la direction encourage votre équipe à aller de l'avant, vous devez leur montrer des faits, tels que le taux de défauts pour chaque version. Le temps passé à réparer les défauts pourrait être mieux utilisé, par exemple pour améliorer l'application et la rendre plus adaptable aux exigences futures.
Si l'équipe et la direction en général sont apathiques à propos de la correction du code et que vous vous sentez mal à l'aise, vous devrez peut-être chercher un autre lieu de travail, à moins de pouvoir les convaincre, comme je l'ai dit. J'ai rencontré ce problème à différents degrés dans tous les endroits où j'ai travaillé. Cela peut aller de l'absence d'un modèle de domaine approprié à une mauvaise communication au sein de l'équipe.
Prendre soin de votre code et de la qualité du produit que vous développez est un bon attribut que vous voulez toujours encourager chez les autres.
la source
Si vous codez en C, Objective-C ou C ++, vous pouvez utiliser CLang Static Analyzer pour critiquer votre source sans l'exécuter.
Certains outils de débogage de mémoire sont disponibles: ValGrind, Guard Malloc sur Mac OS X, Electric Fence sur * NIX.
Certains environnements de développement offrent la possibilité d’utiliser un allocateur de mémoire de débogage qui remplit des tâches telles que le remplissage des pages nouvellement allouées et libérées, la détection de la libération des pointeurs non alloués et l’écriture de certaines données avant et après chaque bloc appelé si le modèle connu de ces données change jamais.
Un gars de Slashdot a déclaré qu'il tirait beaucoup de profit d'une nouvelle source de données à débogage unique dans un débogueur. "C'est ça" dit-il. Je ne suis pas toujours ses conseils, mais ceux-ci m'ont été très utiles. Même si vous n'avez pas de scénario de test stimulant un chemin de code peu commun, vous pouvez modifier une variable de votre débogueur pour prendre de tels chemins, en allouant de la mémoire, puis en utilisant le débogueur pour définir votre nouveau pointeur sur NULL au lieu du paramètre. adresse de mémoire, puis en passant par le gestionnaire d’échec d’allocation.
Utilisez des assertions - la macro assert () en C, C ++ et Objective-C. Si votre langue ne fournit pas de fonction d'assertion, écrivez-en une vous-même.
Utilisez des assertions généreusement, puis laissez-les dans votre code. J'appelle assert () "Le test qui continue à tester". Je les utilise le plus souvent pour vérifier les conditions préalables au point d'entrée de la plupart de mes fonctions. C'est une partie de "Programmation par contrat", qui est intégrée au langage de programmation Eiffel. L’autre partie concerne postconditions, c’est-à-dire assert () à des points de retour de fonction, mais j’aperçois que je n’en retire pas autant de kilométrage que de conditions préalables.
Vous pouvez également utiliser assert pour vérifier les invariants de classe. Bien qu'aucune classe ne soit strictement requise pour avoir un invariant, les classes les plus judicieusement conçues les ont. Un invariant de classe est une condition toujours vraie autre que celle contenue dans les fonctions membres pouvant placer temporairement votre objet dans un état incohérent. De telles fonctions doivent toujours restaurer la cohérence avant leur retour.
Ainsi, chaque fonction membre peut vérifier l'invariant à l'entrée et à la sortie et la classe peut définir une fonction appelée CheckInvariant que tout autre code pourrait appeler à tout moment.
Utilisez un outil de couverture de code pour vérifier quelles lignes de votre source sont effectivement testées, puis concevez des tests qui stimulent les lignes non testées. Par exemple, vous pouvez vérifier les gestionnaires de mémoire insuffisante en exécutant votre application dans une machine virtuelle configurée avec peu de mémoire physique et sans fichier d'échange, ni très petit.
(Pour une raison quelconque, je n'étais jamais au courant, alors que BeOS pouvait fonctionner sans fichier d'échange, il était extrêmement instable de cette façon. Dominic Giampaolo, qui a écrit le système de fichiers BFS, m'a exhorté à ne jamais exécuter le BeOS sans échange. Je ne voyez pourquoi cela devrait être important, mais il doit s'agir d'une sorte d'artefact d'implémentation.)
Vous devez également tester la réponse de votre code aux erreurs d'E / S. Essayez de stocker tous vos fichiers sur un partage réseau, puis débranchez votre câble réseau pendant que votre application a une charge de travail élevée. De même, débranchez le câble - ou éteignez votre réseau sans fil - si vous communiquez sur un réseau.
Les sites Web qui ne disposent pas de code Javascript robuste sont particulièrement irritants. Les pages de Facebook chargent des dizaines de petits fichiers Javascript, mais si l'un d'entre eux ne parvient pas à télécharger, la page entière se brise. Il doit simplement exister un moyen de fournir une certaine tolérance aux pannes, par exemple en réessayant un téléchargement, ou de fournir une sorte de solution de secours raisonnable lorsque certains de vos scripts ne se sont pas téléchargés.
Essayez de tuer votre application avec le débogueur ou avec "kill -9" sur * NIX alors qu'il est en train d'écrire un gros fichier important. Si votre application est bien architecturée, l'intégralité du fichier sera écrit ou ne sera pas écrit du tout, ou peut-être s'il n'est que partiellement écrit, ce qui sera écrit ne sera pas corrompu, avec quelles données sauvegardées seront complètement utilisables par l'application lors de la relecture du fichier.
les bases de données ont toujours des E / S de disque tolérantes aux pannes, mais pratiquement aucun autre type d'application ne le fait. Bien que les systèmes de fichiers journalisés empêchent la corruption du système de fichiers en cas de panne de courant ou de panne, ils ne font rien du tout pour empêcher la corruption ou la perte des données de l'utilisateur final. C’est la responsabilité des applications utilisateur, mais pratiquement aucune autre base de données que la base de données n’implémente la tolérance aux pannes.
la source
Lorsque je teste mon code, je passe généralement par une série de processus de pensée:
Le moyen le plus simple que j’ai trouvé est de développer mes tests avec mon code. Dès que j'ai même écrit un fragment de code, j'aime bien écrire un test. Essayer de faire tous les tests après avoir codé plusieurs milliers de lignes de code avec une complexité de code cyclomatique non triviale est un cauchemar. Ajouter un ou deux tests supplémentaires après quelques lignes de code est très simple.
BTW, ce n'est pas parce que votre entreprise et / ou vos collègues ne font pas de tests unitaires ou de tests TDD que vous ne pouvez pas les essayer, à moins que cela ne soit expressément interdit. Peut-être que les utiliser pour créer du code robuste sera un bon exemple pour les autres.
la source
En plus des conseils donnés dans les autres réponses, je suggérerais d'utiliser des outils d' analyse statiques (Wikipedia possède une liste de plusieurs outils d'analyse statique pour différentes langues ) afin de rechercher les défauts potentiels avant le début des tests et de surveiller certains paramètres liés à la testabilité de code, telle que la complexité cyclomatique , les mesures de complexité de Halstead , ainsi que la cohésion et le couplage (vous pouvez les mesurer avec fan-in et fan-out).
Trouver le code difficile à tester et le rendre plus facile à tester vous facilitera la rédaction de scénarios de test. En outre, la détection précoce des défauts ajoutera de la valeur à l'ensemble de vos pratiques d'assurance de la qualité (y compris les tests). À partir de là, vous familiariser avec les outils de tests unitaires et les outils de moquage vous facilitera la mise en œuvre de vos tests.
la source
Vous pouvez examiner l'utilisation possible des tables de vérité pour vous aider à définir tous les chemins potentiels de votre code. Il est impossible de prendre en compte toutes les possibilités dans les fonctions complexes, mais une fois que vous avez établi votre traitement pour tous les chemins connus, vous pouvez établir un traitement pour le cas contraire.
La plupart de ces capacités particulières sont toutefois apprises par expérience. Une fois que vous avez utilisé un cadre donné pendant un temps considérable, vous commencez à voir les modèles et les marques de comportement qui vous permettront d’examiner un morceau de code et de déterminer dans quels cas un petit changement pourrait provoquer une erreur majeure. Le seul moyen auquel je peux penser pour augmenter vos aptitudes dans ce domaine est la pratique.
la source
Si, comme vous l'avez dit, vous n'avez pas besoin de tests unitaires, je ne vois pas de meilleure approche que d'essayer de casser votre propre code manuellement.
Essayez de pousser votre code à la limite . Par exemple, essayez de transmettre des variables à une fonction dépassant les limites. Avez-vous une fonction censée filtrer les entrées de l'utilisateur? Essayez de saisir différentes combinaisons de caractères.
Considérons le point de vue de l' utilisateur . Essayez d’être l’un des utilisateurs qui utiliseront votre application ou votre bibliothèque de fonctions.
la source
Vos collègues doivent être vraiment exceptionnels pour ne pas suivre TDD ou les tests unitaires et ne jamais générer de bugs, alors à un certain niveau, je doute qu'ils ne réalisent aucun test unitaire eux-mêmes.
Je suppose que vos collègues font plus de tests que prévu, mais comme ce fait n’est pas connu de la direction, l’organisation en pâtit, car la direction a l’impression que les vrais tests ne sont pas effectués et que le nombre de bogues est faible. les tests n'ont pas d'importance et il ne sera pas programmé pour le faire.
Parlez à vos collègues et essayez de déterminer quel type de test unitaire ils font et d'imiter cela. Plus tard, vous pourrez créer un prototype de meilleures méthodes de test unitaire et d'attributs TDD, puis introduire progressivement ces concepts à l'équipe pour une adoption plus facile.
la source
Vous devriez pouvoir obtenir une couverture de ce que vous écrivez même si votre organisation ne dispose pas d'une couverture complète. Comme beaucoup de choses dans la programmation, l'expérience de le répéter encore et encore est l'un des meilleurs moyens d'être efficace.
la source
En plus de tous les autres commentaires, puisque vous dites que vos collègues savent bien écrire des tests qui ne sont pas une voie heureuse, pourquoi ne pas leur demander de vous jumeler avec vous pour la rédaction de certains tests.
La meilleure façon d'apprendre est de voir comment on procède et de tirer ce que l'on apprend de cela.
la source
Test de la boîte noire! Vous devriez créer vos classes / méthodes avec des tests en tête. Vos tests doivent être basés sur les spécifications du logiciel et clairement définis sur votre diagramme de séquence (via des cas d'utilisation).
Maintenant, puisque vous ne voulez peut-être pas faire de développement piloté par les tests ...
Mettez la validation d'entrée sur toutes les données entrantes; ne fais confiance à personne. La structure .net a généré de nombreuses exceptions basées sur des arguments non valides, des références nulles et des états non valides. Vous devriez déjà penser à utiliser la validation des entrées sur la couche d'interface utilisateur, donc c'est la même astuce dans le middle-ware.
Mais vous devriez vraiment faire une sorte de test automatisé; ça sauve des vies.
la source
Dans mon expérience
Unité de test, si ce n'est pas complètement automatique, c'est inutile. C'est plus comme un patron pointu cheveux pourrait acheter. Pourquoi ?, parce que Test Unit vous avait promis de gagner du temps (et de l'argent) en automatisant certains processus de test. Mais, certains outils d'unité de test font le contraire, cela oblige les programmeurs à travailler de façon étrange et oblige les autres à créer des tests trop étendus. La plupart du temps, cela ne fera pas gagner du temps, mais augmentera le temps de déplacement du contrôle qualité au développeur.
UML est une autre perte de temps. un seul tableau blanc + stylo pourrait faire la même chose, moins cher et plus rapidement.
BTW, Comment bien coder (et éviter les bugs)?
a) l'atomicité. Une fonction qui effectue une tâche simple (ou quelques tâches simples). Parce qu'il est facile à comprendre, il est facile à suivre et à résoudre.
b) homologie. Si, par exemple, vous appelez une base de données à l'aide d'une procédure de stockage, faites-le pour le reste du code.
c) Identifier, réduire et isoler le "code de création". La plupart du code est quasiment copié-collé. Le code créatif est l’inverse, un code nouveau et qui fait office de prototype, il peut échouer. Ce code est sujet aux bogues logiques, il est donc important de le réduire, de l'isoler et de l'identifier.
d) Le code "mince" est le code que vous savez qu'il est "incorrect" (ou potentiellement dangereux) mais dont vous avez toujours besoin, par exemple un code non sécurisé pour un processus multitâche. Évitez si vous le pouvez.
e) Évitez le code boîte noire, cela inclut le code qui n'est pas fait par vous (par exemple, le framework) et l'expression régulière. Il est facile de rater un bug avec ce type de code. Par exemple, j’ai travaillé dans un projet utilisant Jboss et j’ai trouvé non pas une mais 10 erreurs dans Jboss (en utilisant la dernière version stable), c’était un PITA pour les trouver. Evitez spécialement Hibernate, il cache la mise en oeuvre, d’où les bugs.
f) ajouter des commentaires dans votre code.
g) entrée de l'utilisateur comme source de bogues. identifiez-le. Par exemple, l'injection SQL est provoquée par une entrée utilisateur.
h) Identifier le mauvais élément de l'équipe et séparer la tâche assignée. Certains programmeurs sont enclins à visser le code.
i) Évitez le code inutile. Si, par exemple, la classe a besoin de Interface, utilisez-la, sinon évitez d'ajouter du code non pertinent.
a) et b) sont la clé. Par exemple, j'ai eu un problème avec un système, lorsque j'ai cliqué sur un bouton (enregistrer), il n'a pas enregistré le formulaire. Ensuite, j'ai fait une liste de contrôle:
Et un sidenote
la source
Un testeur et un programmeur font face au problème sous des angles différents, mais les deux rôles doivent entièrement tester les fonctionnalités et rechercher les bogues. L'accent est mis sur les rôles différents. Un testeur classique ne voit l’application que de l’extérieur (c’est-à-dire une boîte noire). Ils sont des experts sur les exigences fonctionnelles de l'application. Un programmeur est censé être un expert à la fois des exigences fonctionnelles et du code (mais a tendance à se concentrer davantage sur le code).
(Cela dépend de l'organisation si les programmeurs sont explicitement censés être des experts en exigences. Quoi qu'il en soit, l'attente implicite est là - si vous concevez quelque chose de mal, c'est vous (et non la personne qui répond à vos exigences).)
Ce double rôle d’experts pèse sur l’esprit du programmeur et, à l’exception des plus expérimentés, peut réduire la maîtrise des exigences. Je trouve que je dois changer de vitesse mentalement pour prendre en compte les utilisateurs de l'application. Voici ce qui m'aide:
la source
Je pense que vous voulez travailler sur deux fronts. L’un est politique, amenant votre organisation à adopter les tests à un certain niveau (dans l’espoir qu’elle en adoptera de plus en plus avec le temps). Parlez à des ingénieurs d'assurance qualité en dehors de votre lieu de travail. Trouvez des listes de livres d'assurance qualité . Poke autour des articles de Wikipédia pertinents . Familiarisez-vous avec les principes et les pratiques d’AQ. L’apprentissage de ces éléments vous préparera à présenter les arguments les plus convaincants possibles au sein de votre organisation. De bons départements d'assurance qualité existent et ils apportent une valeur ajoutée considérable à leurs organisations.
En tant que développeur individuel, adoptez des stratégies à utiliser dans votre propre travail. Utilisez vous-même TDD en codéveloppant du code et des tests. Gardez les tests clairs et bien entretenus. Si on vous demande pourquoi vous faites cela, vous pouvez dire que vous empêchez les régressions et que votre processus de pensée est mieux organisé (les deux seront vrais). Écrire un code testable est un art , apprenez-le. Soyez un bon exemple pour vos collègues développeurs.
En partie, je prêche moi-même ici, parce que je fais beaucoup moins de ce genre de choses que je ne le devrais.
la source