Pourquoi les tests automatisés échouent-ils dans mon entreprise?


178

Nous avons essayé d'introduire plusieurs fois les tests automatisés pour développeurs dans mon entreprise. Notre équipe d’assurance qualité utilise Selenium pour automatiser les tests d’interface utilisateur, mais j’ai toujours voulu introduire les tests unitaires et les tests d’intégration. Dans le passé, chaque fois que nous essayions, tout le monde était excité pendant les deux premiers mois. Ensuite, après plusieurs mois, les gens cessent tout simplement de le faire.

Quelques observations et questions:

  1. Les tests automatisés fonctionnent-ils réellement? La plupart de mes collègues qui travaillaient dans d’autres sociétés ont essayé sans succès de mettre en œuvre une stratégie de test automatisé. Je n'ai toujours pas vu une société de logiciels de la vie réelle qui l'utilise réellement et ne se contente pas d'en parler. Un si grand nombre de développeurs considèrent les tests automatisés comme quelque chose de génial en théorie mais ne fonctionnant pas en réalité. Notre équipe commerciale aimerait que les développeurs le fassent même avec un coût de 30% de temps supplémentaire (au moins, ils le disent). Mais les développeurs sont sceptiques.

  2. Personne ne sait vraiment comment faire correctement des tests automatisés. Oui, nous avons tous lu les exemples de tests unitaires sur Internet, mais les utiliser pour un grand projet est tout autre chose. Le principal responsable est de se moquer de la base de données ou de tout ce qui n’est pas trivial. Vous finissez par passer plus de temps à vous moquer qu'à écrire des tests réels. Ensuite, quand il faut plus de temps pour écrire des tests que du code, c'est à ce moment-là que vous abandonnez.

  3. Existe-t-il de bons exemples de tests unitaires / tests d'intégration de systèmes utilisés dans des applications Web complexes centrées sur les données? Des projets open source? Notre application est centrée sur les données, mais a également beaucoup de logique de domaine. J’ai essayé l’approche de référentiel à un moment donné et j’ai trouvé que c’était très bon pour les tests unitaires, mais c’est au prix de pouvoir optimiser facilement l’accès aux données et cela ajoute une couche de complexité supplémentaire.

Nous avons un grand projet entrepris par 20 développeurs expérimentés. Cela semblerait être un environnement idéal pour introduire les tests unitaires / tests d'intégration.

Pourquoi ça ne marche pas pour nous? Comment l'avez-vous fait fonctionner dans votre entreprise?


14
Quelle est votre pile technologique?
Florian Margaine

7
Les WebForm sont presque impossibles à tester correctement. Vous pouvez utiliser un modèle MVP (Modèle / Vue / Présentateur) pour déplacer la logique de présentation vers un composant testable.
Pete

12
@MasonWheeler: Dans les deux cas, vous avez construit un argument formidable qui réfute les prémisses qui n'étaient pas acceptées au départ: les tests unitaires existent pour prouver l'exactitude.
Steven Evers

10
@ MasonWheeler - En utilisant cet argument, vous ne devriez jamais tenter aucune assurance qualité, car vous ne prouverez jamais qu'il n'y a pas de bugs. Ce n'est même pas le but. Une bonne stratégie de tests unitaires et d'interface utilisateur automatisée consiste simplement à libérer l'assurance qualité des tests par cœur et à leur permettre de se concentrer sur les tests exploratoires.
Alex

15
Je suis choqué que plusieurs personnes aient déclaré qu'elles n'avaient jamais vu de tests automatisés depuis plus de quelques mois. J'ai travaillé pour environ cinq grandes entreprises allemandes en tant que consultant et elles vous licencieraient si vous n'écriviez pas de tests. Les tests automatisés ne sont pas un sujet théorique, ils sont pratiqués avec succès dans le monde entier et augmentent considérablement la qualité du code (si cela est fait correctement).

Réponses:


89

La partie la plus difficile des tests unitaires consiste à amener la discipline à écrire les tests d’abord / au début. La plupart des développeurs ont l'habitude de se plonger dans le code. Cela ralentit également le processus de développement dès le début, car vous essayez de comprendre comment écrire un test pour le code. Cependant, à mesure que vous améliorez vos tests, cela accélère. Et à cause des tests d'écriture, la qualité initiale du code commence plus haut.

Lorsque vous débutez, essayez simplement d’écrire des tests. Ne vous inquiétez pas tellement de vous moquer ou de vous moquer de choses au début. Gardez les tests simples. Les tests sont codés et peuvent / devraient être refactorisés. Même s’il est difficile de tester quelque chose, cela pourrait aussi être la conception. TDD cherche à utiliser la plupart des modèles de conception (selon mon expérience, en particulier le modèle Factory).

Assurez-vous que les tests ont un niveau de visibilité. Intégrez-les dans le processus de publication, demandez-leur lors de la révision du code. Tous les bugs trouvés devraient faire l'objet d'un test. Ces choses sont où le TDD brille.

Voici quelques ressources que j'ai trouvées utiles:

http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf

http://www.agitar.com/downloads/TheWayOfTestivus.pdf

Modifier:

Une chose à garder à l'esprit lorsque vous écrivez des tests. Vous n'essayez pas de spécifier quoi que ce soit à propos de l'implémentation du code, mais seulement du comportement. Lorsque vous écrivez du code, vous le testez tout le temps. Essayer de l'exécuter avec des instructions de débogage, etc. L'écriture de tests formalise ceci et fournit un enregistrement des tests que vous avez. De cette façon, vous pouvez vérifier vos fonctionnalités en toute confiance sans ignorer accidentellement un scénario de test dont vous vous souveniez au milieu du processus de développement.


Une autre façon de présenter cela comme une fonction de diagnostic ... c'est-à-dire un test POST (Power On Self Test) qui peut presque nous permettre d'envoyer le code client ... et pas simplement un ensemble de tests simples, ce que les tests et les fonctions devraient être.
JustinC

Aussi, évitez TDD Anti-Patterns .
Gary Rowe

4
Misko Hevery publie également sur YouTube des vidéos de qualité sur l’écriture de code testable que j’ai trouvé inestimable. youtube.com/watch?v=acjvKJiOvXw
Despertar

"Assurez-vous que les tests obtiennent un niveau de visibilité" - ceci est essentiel au succès. Si personne ne peut voir comment vos tests fonctionnent, ils ne verront pas la valeur. Les tests doivent être exécutés lors de l’enregistrement automatique dans le cadre d’une intégration continue, puis consignés. Je travaille chez Tesults ( tesults.com ) et sa raison d'être est due à l'énorme impact fourni par la visibilité des tests.
Compétence M2

77

À bien des égards, je suis d’accord avec votre équipe.

  1. La plupart des tests unitaires ont une valeur discutable. Depuis la grande majorité des tests semble être trop simple.

  2. Il est beaucoup plus difficile d'écrire un bon code testable qu'un code fonctionnel. Un grand pourcentage de la communauté des développeurs qui croient qu’il est essentiel de le faire fonctionner, par opposition à la qualité du code / de la conception en soi. Et un pourcentage encore plus important qui ne sait même pas ce qu'est un code de qualité.

  3. L'écriture du code de test unitaire peut prendre beaucoup plus de temps que le code lui-même.

  4. Déterminer comment tester de manière adéquate le code plus compliqué (c'est-à-dire les éléments que vous souhaitez réellement tester à fond) va au-delà des capacités de nombreux développeurs.

  5. Maintenir les tests unitaires prend trop de temps. De petits changements peuvent avoir de gros effets d'entraînement. L'objectif principal des tests unitaires automatisés est de déterminer si les modifications ont violé le code. Cependant, 99% du temps, ce sont les tests et non le code qui finissent par casser.

Avec tous les problèmes ci-dessus, il n’existe toujours pas de meilleur moyen de modifier le code et d’avoir la certitude que quelque chose ne se brise pas de façon inattendue par rapport à l’automatisation de vos tests.

Une partie de ce qui précède peut être atténuée dans une certaine mesure en ne respectant pas le manuel de tests unitaires.

De nombreux types de conceptions / applications sont mieux testés en automatisant les tests au niveau du module / package. D'après mon expérience, la plupart des erreurs de codage ne sont pas dues au fait que le code d'une classe a été mal codé, mais au codeur qui n'a pas compris comment leur classe était supposée fonctionner avec d'autres classes. J'ai vu beaucoup de bénéfices pour ce type de tests. Mais encore une fois, ces tests sont plus difficiles à écrire que les tests unitaires (niveau classe).

Tout se résume à savoir si les développeurs croient ou non au processus. S'ils le font, ils écrivent de bons tests unitaires, trouvent les erreurs tôt et sont des promoteurs. S'ils ne le font pas, leurs tests unitaires seront généralement inutiles et ne trouveront aucune erreur. Leur théorie selon laquelle les tests unitaires seront inutiles sera prouvée (dans leur esprit).

L’essentiel est que je n’ai jamais vu l’approche complète des tests unitaires automatisés fonctionner pendant plus de deux mois moi-même, mais l’idée des tests unitaires automatisés persiste, bien que nous soyons sélectifs quant à ce qui doit vraiment être testé. Cette approche a tendance à avoir beaucoup moins de critiques et est plus acceptée par tous les développeurs que par quelques-uns.


24
J'ai tendance à être d'accord avec cela. Nous avons pris l'habitude de ne faire des tests qu'après quelque chose qui se casse (même si c'était au cours du développement). Jamais au début, prend trop de temps pour trop peu de récompense.
Izkata

5
@ Izkata L’autre approche que j’ai vue réussir consiste à écrire un nombre relativement petit de tests de haut niveau appelant la Frobinate()méthode de niveau supérieur (au lieu des dizaines de méthodes plus petites appelées en dessous) après que le système a été vérifié par un autre moyen de servir comme test de fumée qu'aucun des changements de niveau inférieur n'a rien cassé. Généralement, ces tests ont utilisé les mêmes données que celles incluses dans les tests utilisateur fournis au clavier afin que le client puisse voir que le système fait ce qu'il veut. Ensuite, les outils de couverture de code peuvent identifier les cas où les cas périphériques ne sont pas encore couverts.
Dan Neely

3
Je n'ai pas dit "tests automatisés complets", j'ai parlé de "tests UNIT automatisés complets". Grande différence. J'ai utilisé des tests automatisés au niveau du module pendant au moins une décennie. Les tests unitaires sont au niveau de la classe. Je crois que je suis plus rentable lorsque je teste des classes censées fonctionner ensemble plutôt que individuellement. Cependant, même là, nous utilisons toujours une approche pragmatique et choisissons de manière sélective quoi / où écrire des tests automatisés.
Dunk

2
Sans une bonne couverture de tests unitaires, comment refactorisez-vous? Ou bien, sans refactorisation, comment empêchez-vous le code de dégénérer progressivement en non-maintenabilité?
Kevin Cline

1
@ Leonardo Ils ne l'ont pas fait - ils étaient trop effrayés pour changer quoi que ce soit. Ou bien ils ont économisé toute cette dette technique et mis de côté quelques semaines / mois plus tard pour la régler en une fois.
GraemeF

33

Le principal responsable est de se moquer de la base de données ou de modifier quelque chose qui ne soit pas simple.

Et voilà votre problème.

Tout le monde insiste sur la manière d'intégrer les tests unitaires dans votre environnement. Comment forcer les gens à le faire suffisamment pour qu'ils voient la valeur pratique et que cela «colle». Mais si c'est très pénible à faire et / ou n'apporte aucun bénéfice, cela ne collera pas.

Stubbing sur une base de données devrait être extrêmement simple. Au lieu que votre interface accède à une base de données pour fournir ses résultats, vous insérez un simple objet codé en dur. Si vous ne pouvez pas faire cela, alors votre conception / architecture a des problèmes. Votre code suppose qu'il va dans une base de données ou que vous n'avez pas l'abstraction d'interface pour le faire varier.

Ce n'est pas simplement un problème de test / qualité. Dès que vous souhaitez changer de fournisseur de base de données, ou aller plutôt dans le cloud, ou prendre en charge des applications mobiles non connectées, votre conception échoue tout simplement. Si vous ne pouvez pas prendre en charge les cas de flexibilité les plus simples, vous ne pourrez certainement pas prendre en charge les tâches plus complexes que votre entreprise nécessitera inévitablement.


4
Le codage en dur de la base de données, qui renvoie les valeurs d'un petit objet mock, est un bon moyen d'isoler le test de tout élément de la base de données susceptible de changer et de casser le code (par exemple, renommage de colonnes). Cela convient dans certaines circonstances, mais il est important de conserver une base de données de test temporaire facile à utiliser, sauf si vous souhaitez que les choses se cassent un jour lorsque vous les modifiez. Si votre code se casse lorsque vous échangez la base de données, c'est une erreur du code que le test devrait capturer (et si vous voulez éviter cela, vous voudrez exécuter la suite de tests sous plusieurs bases de données.)

8
@fennec - les tests unitaires ne sont pas là pour tester la base de données, ils sont là pour tester le code qui dépend des valeurs de la base de données pour fonctionner.
Telastyn

3
Tout va bien jusqu'à ce que vous testiez à l'unité le code qui manipule la base de données. : P qui, pour beaucoup de gens, représente beaucoup de leur code.

4
@fennec - C’est un peu plus complexe qu’un simple mort d’éliminer l’interface pour s’assurer que vos écritures écrivent le bon objet. Cela ne devient difficile que lorsque vos classes tentent d’envoyer directement du code SQL par l’interface (lisez: votre conception est horrible).
Telastyn

5
@Telastyn peut-être que je ne comprends pas bien, mais certaines classes doivent finir par se mettre à nu et écrire le code SQL ou écrire le fichier ou envoyer les données ou l'interface avec le GPU. La plupart des prélèvements ont des fuites inévitables à un certain niveau; ils sont simplement pragmatiques et pas nécessairement horribles.
File d'attente des apprentis

21

Vous devez commencer par quelque chose de petit, simple à automatiser et de grande valeur. Arrachez quelques fruits faciles à mettre en place et vous pourrez vendre le processus. Montrez comment cela a permis à quelqu'un de sauver une fin de soirée ou un appel de fin de semaine. Ensuite, vous pouvez développer à partir de là.

Pour bien faire les tests automatisés, vous avez besoin de quelqu'un qui est une ressource et un évangéliste, et qui a acquis le soutien des cadres supérieurs.

Traitez votre développement de test automatisé comme n'importe quel autre projet agile. Produire des tests terminés régulièrement.

Ajout du commentaire: C'est plus un problème de gestion. Le code est-il considéré comme "terminé" avant d'être documenté? Avant qu'il soit enregistré? Avant d'inclure et de réussir les tests unitaires?

Votre approche dépend vraiment de votre rôle. Êtes-vous un pair? Si tel est le cas, montrez aux autres comment il est plus facile pour votre code de le réutiliser et de le gérer. Êtes-vous un plomb? Choisissez votre programmeur qui a le plus de problèmes de code et aidez-le à ajouter des tests pour les éviter. Êtes-vous un patron? Définissez comme norme que "le code n’est pas terminé tant que les tests unitaires ne sont pas passés et ne passent pas.


17
"Arrachez des fruits faciles et faciles, et vous pourrez vendre le processus.": Je pense qu'ils en sont déjà à ce stade (ils ont vu les avantages potentiels de l'utilisation de tests unitaires) et c'est pourquoi ils ont été convaincus de le donner. un essai. Le problème est plutôt de savoir comment adapter les résultats à la pratique systématique des tests unitaires. Le seul projet sur lequel j'ai travaillé et qui utilisait systématiquement des tests unitaires comportait plus de code de test unitaire que de code de produit réel. Si une équipe n'est pas prête à passer plus de temps à coder des tests unitaires que le code de l'application réelle, l'approche OMI ne fonctionnera probablement pas.
Giorgio

4
C'est plus un problème de gestion. Le code est-il considéré comme "terminé" avant d'être documenté? Avant qu'il soit enregistré? Avant d'inclure et de réussir les tests unitaires? Votre approche dépend vraiment de votre rôle. Êtes-vous un pair? Si tel est le cas, montrez aux autres comment il est plus facile pour votre code de le réutiliser et de le gérer. Êtes-vous un plomb? Choisissez votre programmeur qui a le plus de problèmes de code et aidez-le à ajouter des tests pour les éviter. Êtes-vous un patron? Définissez comme standard que "le code ne sera pas terminé tant que les tests unitaires ne seront pas passés et ne passeront pas.
Skip Huffman

1
@ SkipHuffman, votre commentaire doit être ajouté en tant que modification à la réponse actuelle.
Radu Florescu

15

Suivez ces règles de base. Tests:

  1. doit courir régulièrement! Vous pouvez effectuer des tests sur chaque build, avant / après chaque enregistrement ou juste tous les matins. Le déclenchement automatique est hautement préférable au déclenchement manuel. Parce qu'en théorie, tous les membres de l'équipe sont responsables de l'exécution des tests. Si ce n'est pas automatisé, cela ne se produit probablement pas assez souvent! Et si vous n'exécutez pas assez souvent vos tests, ils trouveront tous les deux le bogue trop tard, ce qui encouragera de nombreux tests cassés, ce qui conduit au point 2:

  2. Vous ne réussirez toujours que si ces tests, qui se déroulent maintenant régulièrement, ne vous gênent pas . On entend par tests:

    une. ne doit pas prendre trop de temps (subjectivement) pour la valeur qu'ils fournissent! Faites vos tests flambant vite. Ne laissez pas les gens enregistrer des tests qui vont être une perte de temps pour les laisser courir!

    b. ne doit pas être fiable. Évitez les tests multithreads dans la mesure du possible. Appliquez des pratiques d'ingénierie à vos tests, tout comme votre autre code: en particulier, vérifiez le code de vos tests!

    c. ne doit pas être plus difficile à réparer et à maintenir que le code réel testé. Votre vélocité de codage va vraiment être nulle si un petit changement d'une ligne dans votre base de code vous oblige à effectuer 10 tests différents.

Enfin, règle numéro 3. Les tests doivent non seulement échouer pour fournir une valeur négative, comme dans la règle 2, ils doivent aussi fournir une valeur positive. Tests ...

  1. doit vraiment vous dire quelque chose qui vous tient à cœur quand ils échouent! (Pas de tests avec des messages d'erreur obscurs, ou simplement des plaintes ridicules comme "tu as oublié de faire le test sur une machine Windows 2008", s'il te plaît!).

Un moyen populaire de violer la règle n ° 3 est de tester la mauvaise chose . Cela est parfois dû à un test trop grand ou trop flou. Mais cela vient généralement du fait de ne pas tester quelque chose qui importera à un client et de tester des détails de mise en œuvre non pertinents. (Mais parfois, tester les détails de la mise en œuvre est également un test efficace - à l’OMI, il suffit de s’entraîner pour décider lequel.)

Conclusion: ces règles de base vous orientent dans la direction d’une discipline de l’essai durable , ce dont vous avez désespérément besoin. Lors du test, demandez-vous si ce test est vraiment durable et maintenable. Rappelles toi:

  • si les tests ne sont pas durables, ils tombent en désuétude et deviennent de ce fait un effort inutile
  • si les tests ne sont pas viables, vous cessez de faire des tests et votre équipe ne s'améliore plus en test! Et, dernier point:

Le test est réellement difficile. Vous devez vous attendre à ce que les tests de votre équipe soient vraiment mauvais quand vous commencez à écrire des tests . Ne vous découragez pas. Ne jetez pas les vieux tests, chaque fois que vous remarquez qu'ils sont nuls et insoutenables.


12

1. Ça marche vraiment?

Oui, si - correctement. Le fait est que les testeurs doivent ajuster et étendre leurs scripts automatisés après que les ingénieurs ont implémenté de nouvelles fonctionnalités.

2. Personne n’est vraiment expérimenté ni ne sait comment effectuer correctement des tests automatisés.

Obtenez un consultant (quelqu'un qui sait comment faire correctement). Ou investissez plus de temps. L'alternative consiste à avoir une équipe de test plus importante, qui effectue les mêmes tests manuellement (ce qui est sujet aux erreurs).

3.Nous avons un gros projet avec 20 bons développeurs expérimentés. L’introduction des tests unitaires / tests d’intégration devrait donc être un bon environnement. Pourquoi ça ne marche pas pour nous? Comment l'avez-vous fait fonctionner dans votre entreprise?

Je ne les appellerais pas "de bons développeurs expérimentés" s'ils refusaient de faire des tests unitaires. Il existe de nombreux articles sur les avantages des tests (tests unitaires et d'intégration), et à la fin, cela revient à dire combien un bogue coûte à votre entreprise . Par exemple, je travaille dans une entreprise où la qualité est importante, donc les tests unitaires et d'intégration sont inévitables. Vous pouvez facilement trouver de nombreux articles indiquant que seuls les tests unitaires réduisent le nombre de bugs de 30%! (En réalité, il se situe entre 20 et 90%, en moyenne 30%, mais c'est toujours beaucoup.)

Pour que cela fonctionne dans votre entreprise, embauchez un consultant ou confiez cette tâche à un ingénieur en chef (cela lui prendra un certain temps). Et ensuite, forcez tout le monde à respecter les règles.


20
Je dois souligner que pratiquement TOUT fonctionne "si c'est fait correctement". Cependant, ce n’est pas très utile pour tous mais une très petite minorité de la population. Pour qu'un processus puisse réellement prétendre que cela fonctionne, il doit également fonctionner lorsqu'il est terminé "en quelque sorte".
Dunk

11
Je soulignerai que la généralisation excessive de la situation de chacun à la vôtre (c’est-à-dire que je ne les appellerais pas "bons développeurs expérimentés"… est une question de qualité) ne démontre pas seulement votre manque d’expérience, mais n’est pas très productive. Chaque industrie a sa propre définition des "œuvres"; et quels tests de degré doivent être effectués aux niveaux de l'unité, de l'intégration et du système. De nombreux développeurs "exceptionnellement bons" ont compris que les tests unitaires ne rapportaient pas grand chose en comparaison des tests d'intégration automatisés. Ils réalisent également que cela ne s'applique probablement qu'à leur secteur d'activité
Dunk

11
"Je ne les appellerais pas de" bons développeurs expérimentés "s'ils refusaient de faire des tests unitaires." Ce n'est que l'erreur No True Scotsman. Pendant des décennies, l’industrie du logiciel s’est débrouillée sans tests unitaires et la plupart de ces industries continuent de s’en passer, de nos jours. C'est peut-être une bonne idée mais ce n'est tout simplement pas obligatoire.
Noah Yetter

1
"Ne perdez pas de temps en tests unitaires": Je reformulerais cette phrase en "Ne perdons pas de temps en tests unitaires inutiles". Tout en aveugle, tout tester peut entraîner une énorme perte de temps.
Giorgio

1
@Dunk Je déteste vraiment tout le phénomène test-premier-tout-TDD, mais je ne peux pas accepter votre première déclaration. Vous faites bien les choses ou vous ne les faites pas. Vous pouvez bien tester une unité et peut-être en voir le bien-fondé, mais vous ne verrez jamais le mérite d'une chose faite à moitié cul.
Erik Reppen

10

Il existe de nombreuses raisons pour lesquelles l'introduction de tests automatisés peut échouer. Je pense que cela revient au fait que les programmeurs ont tendance à ne pas changer leurs habitudes de codage et ne sont pas totalement capables d’accepter les tests unitaires.

De nombreuses personnes souhaitant commencer par des tests automatisés essaient de les introduire pour une base de code existante. Ils essaieront d’écrire des tests d’intégration qui testeront simultanément de nombreuses fonctionnalités d’une application existante. De tels tests d'intégration sont notoirement trop difficiles et trop coûteux à maintenir. Conseil: Introduisez des tests automatisés pour une nouvelle base de code.

Les tests unitaires sont de bons tests à automatiser. Tout ce qui précède (tests d'intégration, tests de composants, tests de système) peut également être testé automatiquement, mais le rapport coûts-avantages diminue rapidement, plus le nombre de fonctionnalités testées est simultané. Cet effet négatif est amplifié si vous construisez de tels tests sur des fonctionnalités mal testées. Conseil: Introduisez des tests automatisés au niveau des tests unitaires et construisez des tests d'intégration automatisés sur une base solide de tests unitaires .

D'après ce qui précède, le succès des tests automatisés dépend en grande partie de l'efficacité des tests unitaires. Vous avez des tests unitaires efficaces si vous vous sentez productif avec les tests unitaires. Lorsque les gens commencent avec les tests unitaires, ils ont tendance à adapter leur code et leurs habitudes de codage existants aux tests unitaires. Ironiquement, c'est le moyen le plus difficile d'apprendre les tests unitaires. De plus, le test unitaire nécessite de changer la façon dont vous codez (en appliquant par exemple les principes SOLID ). La plupart des programmeurs arrêtent bientôt d'écrire les tests unitaires car ils pensent que la courbe d'apprentissage est trop raide et trouvent qu'il est difficile de placer des tests unitaires autour d'un code conçu qui ne soit pas aussi testable. Conseil: Apprenez les tests unitaires à partir de zéro avec le nouveau code et traitez le fait que vous devez changer vos habitudes de codage.

Il y a beaucoup d'autres facteurs, mais j'ai trouvé que pour la plupart des programmeurs, il est difficile de changer de code. Le code écrit sans test est simplement différent. Si vous ne pouvez pas insérer votre code dans une conception testable, vous échouerez probablement dans l’écriture de tests unitaires efficaces. Cela détruit le terrain pour des tests automatisés efficaces.

J'en ai fait l'expérience moi-même et je suis maintenant heureux de travailler dans une entreprise qui a introduit avec succès des tests automatisés. Je pourrais écrire beaucoup plus sur les autres facteurs, mais je pense que les habitudes de codage et les tests unitaires sont les plus importants. Heureusement, il y en a d'autres qui ont plus d'expérience que moi et qui remplissent des livres avec leur savoir-faire. L’un de ces ouvrages est le développement d’applications de sites contaminés dans .NET que je peux vraiment vous recommander, car vous utilisez la pile technologique de Microsoft.


Introduce automated tests on the unit test level and build automated integration tests on a solid foundation of unit tests.+1
c69

10

Une chose que je n'ai pas vu clairement traitée dans les réponses ci-dessus est que le test unitaire est essentiellement un bien public et un coût privé. J'ai écrit un article de blog à ce sujet ici .

En fin de compte, si une série de tests bénéficie à l'équipe ou à un développeur individuel, la rédaction du test représente un coût pour celui qui la réalise, la plupart du temps.

En bref, à moins que l’ écriture du test ne soit imposée d’une manière ou d’une autre (et les réponses ci-dessus énumèrent un certain nombre de façons différentes de le faire), il n’ya aucune raison pour qu’un développeur en particulier le fasse.

Dans une entreprise dans laquelle j'ai travaillé, l'écriture de tests unitaires était indispensable pour fournir une fonctionnalité. Le nouveau code n'a été accepté que si un test unitaire faisait partie de la validation ou de la nouvelle fonctionnalité - de brèves révisions du code pour chaque "tâche" donnée à un développeur. Il peut être intéressant de mettre en place une politique similaire sur votre lieu de travail.


8

Il est intéressant de noter que le business est plus pro-test que les développeurs! Il me semble que votre plus grand défi sera de surmonter la résistance de vos développeurs au changement; ils doivent redéfinir leur compréhension de leur travail pour inclure les tests unitaires.

Rien ne peut vous aider davantage que les premiers succès des tests unitaires pour aider vos développeurs à surmonter leur résistance à la rédaction de ces tests. Si vous les incitez à faire quelque chose de nouveau, assurez-vous de commencer par obtenir une récompense presque garantie.

@SkipHuffman en a parlé, mais je vais le dire tout de suite. Certaines choses sont beaucoup plus adaptées aux tests automatisés que d’autres. Pour le premier passage, je ne testerais PAS la base de données ou l'interface utilisateur. Les entrées d'une base de données peuvent être extrêmement difficiles à configurer et à démonter. Les tests de sortie d’UI ont tendance à être rapidement interrompus par des modifications d’apparence totalement étrangères à vos tests.

Ce que j'appellerais "middleware" est parfait pour les tests unitaires. Code qui a des conditions d'entrée et de sortie clairement définies. Si vous suivez le principe DRY (Ne vous répétez pas), vous aurez écrit quelques petites classes ou fonctions pour résoudre des problèmes récurrents propres à votre application.

Les tests unitaires sont un excellent outil pour limiter le risque de modification des composants internes existants. Ecrivez des tests unitaires avant de modifier un composant interne ayant fonctionné longtemps. Ces tests prouvent que la fonctionnalité qui fonctionne actuellement est préservée. Lorsque vous avez effectué votre modification et que tous les tests unitaires sont réussis, vous savez que rien n’a été cassé «en aval». Si vous trouvez un problème en aval, ajoutez un test unitaire pour celui-ci!

Ron Heifitz dirait: " Résoudre les conflits entre les valeurs que les gens attachent ou réduire l'écart entre les valeurs qu'ils défendent et la réalité à laquelle ils sont confrontés. Le travail d'adaptation nécessite un changement de valeurs, de croyances ou de comportement". Après avoir surmonté la résistance humaine au changement, vous pouvez vous lancer dans des zones de test plus difficiles, le cas échéant.


6
"vaincre la résistance de vos développeurs au changement": toutes les résistances ne sont pas sans raison et il ne faut pas éviter une discussion honnête en utilisant l'argument "résistance au changement".
Giorgio

7

Une chose à propos des tests automatisés est que cela nécessite que vous écriviez du code pour pouvoir être testé. Ce n’est pas une mauvaise chose en soi (en fait, c’est bien parce que cela décourage de nombreuses pratiques qui devraient en principe être évitées), mais si vous essayez d’appliquer des tests unitaires au code existant, il y a de fortes chances que ce ne soit pas le cas. été écrit de manière testable.

Des éléments tels que singletons, méthodes statiques, registres, localisateurs de services, etc., introduisent des dépendances très difficiles à simuler. Les violations de la loi de Demeter signifient qu'un trop grand nombre de parties de votre base de code en savent trop sur le fonctionnement d'autres parties de votre base de code, ce qui introduit d'autres dépendances cachées qu'il peut être difficile de casser. Toutes ces choses rendent difficile l'isolement d'un module du reste de la base de code, et si vous ne pouvez pas tester vos modules de manière isolée, les tests unitaires perdent beaucoup de leur valeur. Si un test échoue, cela est-il dû à une défaillance de l'unité testée, ou à une défaillance de l'une de ses dépendances, ou peut-être est-ce dû au fait que les données extraites via une source de données dépendante ne sont pas attendues par le rédacteur de test ? Si tu peux'

La plupart des bases de code que j'ai observées et qui n'ont pas été conçues avec les tests unitaires à l'esprit ont tendance à être fondamentalement impossibles à tester, car les codeurs ont tendance à se concentrer sur l'utilisation du code comme ils le devraient. . Le code qui a été écrit en pensant aux tests unitaires a l’air très différent.

Beaucoup de gens adoptent une approche naïve des tests unitaires lorsqu'ils commencent à le faire pour la première fois. Ils pensent pouvoir simplement écrire une charge de tests pour une base de code existante et tout ira bien, mais cela ne marche jamais comme ça à cause des les questions mentionnées ci-dessus. Ils commencent à découvrir qu'ils doivent exécuter des quantités excessives de configuration dans les tests unitaires pour pouvoir les exécuter. Les résultats sont souvent discutables, car le manque d'isolation dans le code signifie que vous ne pouvez pas localiser la cause d'un échec du test. Ils ont également tendance à commencer par essayer d’écrire des tests "intelligents" qui démontrent un aspect très abstrait du fonctionnement du système. Cela a tendance à échouer car un test unitaire "intelligent" est en soi une source potentielle de bugs. Le test a-t-il échoué à cause d'un bogue dans le module testé, ou à cause d'un bug dans le test? Un test devrait être tellement simple qu'il est évidemment impossible qu'un bogue s'y cache. En fait, les meilleurs tests durent rarement plus de 2 lignes, la première indiquant à l’équipe testée de faire quelque chose, la seconde affirmant que ce qu’elle a fait est conforme aux attentes.

Si votre équipe souhaite sérieusement adopter les tests unitaires, il ne serait pas judicieux de commencer par un projet existant. Les projets existants de votre équipe ne sont probablement pas testables sans refactorisation majeure. Vous feriez mieux d'utiliser un nouveau projet comme base d'apprentissage sur les tests unitaires, car vous avez une table blanche pour travailler. Vous pouvez concevoir la nouvelle base de code de manière à favoriser l’injection de dépendances par rapport aux singletons, aux registres et autres dépendances cachées, vous pouvez l’écrire en fonction des interfaces plutôt que des implémentations, etc. Vous pouvez également (et devriez) écrire les tests avec le code testé, car l'écriture ultérieure des tests aboutit à des tests unitaires garantissant que le module testé fait ce que vous pensez qu'il est censé faire plutôt que ceux qui le testent. ce que les spécifications disent qu'il devrait faire.

Une fois que vous aurez acquis une certaine confiance dans les tests unitaires, votre équipe commencera probablement à comprendre les failles de son code existant qui vont faire obstacle aux tests unitaires. C’est à ce moment-là que vous pouvez commencer à travailler à la refactorisation du code existant pour le rendre plus testable. Ne soyez pas ambitieux et essayez de faire tout cela en même temps, ou tentez de remplacer un système qui fonctionne par un tout nouveau, commencez simplement par trouver les éléments de la base de code qui peuvent facilement être testés (ceux qui ne le sont pas. dépendances ou où les dépendances sont évidentes) et écrivez des tests pour celles-ci. Je sais que j'ai dit que l'écriture d'un test avec le code était préférable à l'écriture de tests après, mais même un test écrit plus tard a toujours une valeur comme point de départ. Ecrivez les tests comme si vous ne saviez rien du fonctionnement de la classe, si ce n’était ce que ses spécifications prévoient de faire. Lorsque vous exécutez les tests et obtenez des échecs, les spécifications ou l'implémentation sont incorrectes. Vérifiez deux fois pour déterminer ce qui est faux et mettez à jour le test ou le code en conséquence.

Une fois que vous avez récolté les fruits faciles, votre vrai travail commence. Vous devez commencer à rechercher les dépendances cachées dans votre base de code et à les corriger, une à la fois. Ne soyez pas trop ambitieux à ce stade, tenez-vous en à ne faire qu'un module à la fois, ou même un seul problème dans un module, jusqu'à ce que les obstacles au test soient corrigés et que vous puissiez passer au suivant.

TL: DR: La plupart des gens pensent que les tests sont faciles et que vous pouvez facilement intégrer des tests dans du code existant. Ces deux hypothèses sont fausses. Si vous vous lancez dans un projet visant à intégrer des tests unitaires à vos projets en gardant à l'esprit ces deux faits, vous aurez plus de chances de réussir.


Astuce: mettez le TL; DR: en haut - je devais lire tout votre message juste pour y arriver! (ce qui annule le point)
gbjbaanb

4
  • Y a-t-il quelqu'un dans votre entreprise qui possède une vaste expérience des tests automatisés?

Sinon, les initiatives de test automatisé échoueront probablement. Le test automatisé est une compétence, comme bien d’autres compétences en programmation, et si vous n’avez aucune expérience en la matière, il n’est pas facile de dire si un test automatisé est un bon test automatisé avec une valeur réelle ou mauvais. échouer de manière aléatoire / nécessiter des mises à jour fréquentes / n'exerce aucun code intéressant.

  • Est-ce que cette personne a un pouvoir de leadership? Sont-ils capables d'exiger le changement?

Si personne n'écoute, peu importe qu'ils disent que le test n'est pas bon. (Notez qu'il n'est pas nécessaire de formaliser le pouvoir du leadership. Avoir une équipe qui se soucie, c'est bien aussi.)

  • Développez-vous des outils et des processus facilitant la mise en œuvre et l’intégration des tests automatisés dans le cycle de développement?

Les développeurs sont paresseux. Vous devez rendre les choses que vous voulez qu'elles soient faciles à accomplir et celles que vous ne voulez pas qu'elles fassent plus difficiles à accomplir. Vous devez vous assurer que les bibliothèques de test facilitent la réalisation des tâches associées à la configuration de test et au démontage, en particulier la configuration liée à l'environnement, telle que les bases de données de test ou similaires. (La base de données est abordée dans certains de ces commentaires mais doit être utilisée avec prudence. Une véritable base de données doit être facile à créer et vous permettre de tester l'interaction des composants et les cycles de vie des processus, souvent plus importants et plus efficaces que les tests unitaires. un accesseur de données individuel.)

Vous devez également vous assurer que vos IDE disposent d'un bon moyen de lancer la suite de tests. Vous devez exécuter la suite de tests souvent pour que les gens remarquent son échec au lieu de le laisser traîner dans la misère. Les développeurs répondent également bien aux commentaires, par exemple un système d'intégration automatisé annulant leurs modifications s'ils ont réussi un test. Ou, mieux, un retour positif: un système d’intégration automatisé qui détecte les bugs et vous évite de tout casser.


Je ne pense pas qu'il soit juste de dire que les développeurs sont paresseux. C'est peut-être le cas dans votre expérience, mais ce n'est sûrement pas une vérité universelle.
Sam

4

Premièrement, si vos développeurs ne voient pas la valeur de vos tests, c'est probablement parce que vos tests ne sont pas utiles, et non pas parce qu'ils sont aveugles à leur valeur ou à la valeur des tests en général. Parmi ses évangélistes, il y a une tendance à croire que le développement piloté par les tests ne peut échouer, il peut simplement échouer par les développeurs paresseux et paresseux. Je pense que c'est faux et contre-productif.

Quand on m'a initié au développement piloté par les tests, cela signifiait, en effet, écrire un test pour vérifier qu'une méthode qui n'échouera jamais n'échouera jamais. Ce qui est bien, au début, parce que vous obtenez un joli chèque vert et un sentiment d'accomplissement. Plus tard, après avoir refactorisé le code, vous avez des dizaines de Xes rouges exaspérants, dont aucun ne dit plus que le code a changé, que les tests ne sont plus valides et que vous avez perdu beaucoup de temps à les écrire.

Vous voulez éviter ça.

Depuis lors, j'ai adopté une approche différente des tests. Au lieu d'une paire d'implémentation d'interface , j'ai une interface, une implémentation, un test triple . L'interface spécifie le comportement, l'implémentation effectue le comportement, le test vérifie le comportement.

Je suppose que cela semble évident, mais à mon avis, cela fait une distinction entre le code que vous devez prouver et les travaux spécifiés et le code que vous pouvez tester autant ou aussi peu que vous le jugez approprié. Le code que vous devez prouver est l'interface que vous proposez à l'extérieur. le reste ne concerne que vous.

Dans ce cas, je demanderais aux développeurs s'ils voient dans le code une division naturelle dans laquelle ce type de test serait approprié. Existe-t-il une interface implémentée par l'équipe A et utilisée par l'équipe B? Dans ce cas, il est dans l’intérêt de l’équipe B de s’assurer que l’interface se comporte comme prévu. Demandez à l’équipe B d’écrire un test, puis demandez à l’équipe A de s’assurer que leur implémentation est conforme au test; ou, si ce n'est pas le cas, et ce n'est pas intentionnel, discuter du changement imprévu avec l'autre équipe, afin qu'elle puisse s'y préparer.

Je pense que cela illustrerait la valeur du test. Ce n'est pas une fin en soi, malgré les beaux chèques verts. Il existe pour rendre explicite la promesse faite par un développeur à un autre et pour s'assurer que la promesse est tenue à la satisfaction des deux.


1
J'aime le code que je lis mieux que le code qui, de l'avis de quelqu'un, devait être testé jusque dans les moindres détails.
Erik Reppen

1
Je pense que les jolies tiques vertes sont le problème - cela fait de l’essai une sorte de jeu.
gbjbaanb

2

L'ajout de nombreux tests unitaires à un grand projet préexistant est un travail difficile. Si vous avez déjà trouvé un bon framework moqueur qui fonctionne pour vous, vous devriez avoir résolu le problème le plus difficile.

Je suggère d'essayer d'ajouter des tests au fur et à mesure que vous ajoutez des fonctionnalités / corrigez des bugs. La correction des bugs étant la plus facile. Ecrivez un test qui échoue à cause de votre bogue puis corrigez-le. En même temps, vous vous retrouverez probablement en train d'écrire des tests simples qui réussissent. Bien sûr, vous voulez vraiment utiliser un petit morceau de code facilement testé pour cela.

Une fois que les gens commencent à s’habituer à écrire des tests pour les choses les plus faciles, vous devriez espérer qu’ils écrivent leur code pour être plus testables.

Je vous recommanderais également de mesurer la couverture de code de vos tests (j'ai déjà utilisé cobertura for Java). Vous souhaiterez qu'un serveur d'intégration continue exécute les tests et produise les métriques de manière régulière (chaque jour, chaque enregistrement). Si vos collègues développeurs sont enthousiastes, ils voudront voir la couverture augmenter avec le temps et ils pourront voir les lacunes béantes de la couverture dans certains de vos domaines.


2

Je pense que vous devrez peut-être jouer au long jeu. Une des choses que vous pouvez faire pour obtenir une certaine acceptation est d’essayer de tester de manière exhaustive la prochaine fonctionnalité que vous écrivez, puis de garder une trace du nombre de bogues au fil du temps. Vous devriez espérer que les bugs majeurs seront détectés tôt (en particulier si vous associez ceci à une conception pilotée par les tests) et que le nombre de régressions devrait être très faible. Après un certain temps, disons 1 an, comparez les statistiques avec des fonctionnalités de même complexité non testées par l'unité. Si vous pouvez montrer que le nombre de nouveaux bogues et régressions est sensiblement inférieur, vous en fournissez une justification financière et il devient plus difficile à ignorer pour l'équipe produit.

J'étais dans une situation où j'ai pu utiliser TDD et les tests unitaires pour une fonctionnalité majeure. Après la fin de la phase de développement, aucun bug n'a été signalé en plus de 5 ans. Lorsqu'une nouvelle amélioration - et risquée - était demandée, j'ai pu l'implémenter et capturer toutes les régressions dans les tests unitaires.


1

Je suis fermement convaincu que la valeur des tests unitaires est largement sous-estimée par de nombreuses équipes en raison de plusieurs facteurs, dont beaucoup ont déjà été soulignés dans les réponses.

Les développeurs subissent souvent des pressions pour «faire avancer les choses». Il est donc suffisant de prouver que le fonctionnement d'un bloc de code est une preuve suffisante pour le client. Cela s'applique presque toujours aux sociétés de conseil et aux QA axés sur l'homme: si le client ne nécessite pas de tests unitaires et considère une démonstration en direct suffisante, il échoue totalement puisqu'il doit signer une approbation pour le code susceptible de masquer des erreurs.

Les développeurs sont souvent frustrés. Être programmeur est un travail difficile: terminer une tâche et passer à la suivante est satisfaisant, alors tout le monde veut se dépêcher et finir. Jusqu'à ce qu'ils soient touchés par un bus avec un bug majeur qui se développe des mois après l'assurance qualité initiale. Dans ce scénario, le contrôle qualité automatisé et continu est un problème de gestion plutôt que de développeur (ils seront tout de même payés pour leur travail, peut-être des heures supplémentaires).

Mais il y a une exception

Je crois fermement que l'acceptation du modèle de test automatisé est fonction de "l'humain" des tests en cours. Si vous testez un module Web avec une interface utilisateur, vous êtes plus susceptible, malgré des outils tels que Selenium, de remplir le formulaire vous-même, de voir le résultat et de croire en le déterminisme. Vous oublierez de refaire les tests plus tard ou vous serez trop paresseux pour refaire les tests précédents, et c'est pourquoi les bogues sont parfois découverts plus tard. Pour tirer parti de cela, une forte modularisation du code et des règles strictes sur la "modification de l'ancien code" se sont révélées acceptables dans un environnement bancaire (dans mon expérience professionnelle personnelle).

Au lieu de cela, si le développeur est chargé de développer un module de données hautement automatisé et à volume élevé, il sera plus susceptible d'écrire des tests unitaires approfondis et de les soumettre aux lots de test. En effet, le remplissage d'une charge utile XML importante avec des données converties à partir d'une source de données externe (simulée ou non) n'est pas une tâche à prédominance humaine. Certains développeurs de tests finiront par créer un front-office minuscule et amusant pour ce type de tests spécifique. Lorsque je travaillais sur mon mémoire de maîtrise, je travaillais sur un bus de journalisation qui gérait plus de 6 000 messages Syslog par seconde et je devais mesurer la perte et la corruption des paquets: j’ai naturellement rédigé des tests unitaires et des tests de résistance pour presque tous les composants, en particulier l’analyseur Syslog.

Afin de rendre les développeurs plus sujets aux tests unitaires

Je crois qu'ils doivent être obligés de. Si vous êtes un client intelligent, vos consultants devront exécuter la suite de tests complète à chaque contrôle qualité. Si vous êtes un bon chef d'équipe, vous pouvez peut-être attribuer la tâche suivante à un développeur intelligent: créer une plate-forme de test interne. Cela n'a rien à voir avec l'antipatter interne de la plateforme d'effets, mais plutôt un ensemble de classes d'assistance, de bases de données mock, de configurations, d'analyseurs syntaxiques, de convertisseurs, de couteaux suisses pour aider les développeurs à construire des tests en un rien de temps.

Les plates-formes de test actuelles telles que NUnit sont polyvalentes et vous permettent de vérifier des assertions génériques. L'utilisation correcte d'injection de dépendance et d'usines spécifiques à un projet aide les développeurs à écrire moins de code pour les tests et à être plus heureux. Je n'ai pas encore eu la chance d'expérimenter cela sur un projet complet, je ne peux pas donner de retour d'expérience.


1

Les tests automatisés s'apparentent au développement de logiciels. Malheureusement, les personnes que vous embauchez pour les tests sont initialement conçues pour rédiger des scénarios de test, des plans, une stratégie, suivre le processus de révision, tester et consigner manuellement les bogues.

Dès qu’ils se voient confier des responsabilités en matière de tests automatisés, cela inclut une partie du développement logiciel. Le problème ici est que les tests automatisés, quels que soient les outils que vous utilisez (et ne craignons pas, ne discutez pas de ce point), nécessitent un entretien et une mise à jour quotidiennement. Comme les développeurs changent de code,

  • vous devez vous assurer que les tests continuent à s'exécuter.
  • Vous devez vous assurer que les tests ne sont pas supprimés car ils n'ont pas été exécutés.
  • vos métriques de test doivent montrer ce que vous avez exécuté sur la dernière génération et cette génération. Pour vous assurer que votre nombre de cas de test ne diminue pas.
  • Les cas de test doivent être examinés, tout comme le développement, pour s'assurer que les utilisateurs ne s'en mêlent pas. Un peu plus d'un test en deux, juste pour augmenter les chiffres (parfois, les tests sont externalisés, ce suivi est donc important).
  • une communication plus "saine" entre dev et test est importante
  • garder des non-functionaltests séparés, et ne vous attendez pas à courir tous les jours, il faut du temps pour garder ces UpToDate, et bon. Mais n'abandonnez pas, assurez-vous qu'ils sont maintenus.

Vous échouez pour ces raisons

  • vos ingénieurs de test sont des ingénieurs de test manuel sans compétences analytiques. ils ne savent pas la différence entre un ifet une whileboucle. Parce que franchement aucun cours n'enseigne les tests automatisés, ils n'enseignent que les tests manuels.
  • vos ingénieurs de test sont trop occupés par les tests manuels de vos builds et la consignation des bogues afin de perdre la trace des tests automatisés
  • vos gestionnaires de tests ne se soucient pas des métriques des tests automatisés, simplement parce qu'elles affichent des données non valides (au début du projet), et qu'elles ne mettent pas d'effort ou de priorité dans les réunions et les réunions quotidiennes pour souligner à quel point il est important que l'automatisation soit opérationnelle et opérationnelle
  • vous choisissez d'automatiser les tests pour les applications mobiles, dont la durée de vie est très courte. au moment où vous écrivez, stabilisez la suite de tests automatisés, les exigences de votre application changent, vous devriez plutôt vous concentrer sur le test de vos services Web qui exécutent votre application.
  • vous ne comprenez pas que l'équipe de test automatisée suit le même jalon: équipe de développement, fonctionnalité complète, code complet, verrouillage du code et gel du code.
  • vous ne faites pas la différence entre les utilisateurs de tests manuels et les utilisateurs de tests automatisés.
  • ils reçoivent tous deux le même salaire et relèvent du même responsable. Idéalement, ils doivent rendre compte au responsable du développement et leurs salaires doivent correspondre à ceux du développement.
  • vous pensez réellement que Junit n'est pas suffisant pour développer des tests automatisés :).

Celles-ci sont issues de mon expérience de travail pour des entreprises qui prennent les tests automatisés très au sérieux et comprennent que dev est important en tant qu'ingénieur de tests automatisés. Et d'après mon expérience de travail pour des gens qui ne savent pas, comprenez la différence, peu importe combien vous leur expliquez.


Dans le cas des tests unitaires et des tests d'intégration, les personnes chargées de rédiger les tests sont les développeurs et non des "ingénieurs de test" distincts. (Comme indiqué dans la question, l'assurance qualité, c'est-à-dire les ingénieurs de test, utilisent déjà déjà des tests automatisés de l'interface utilisateur.)
Paŭlo Ebermann

De manière réaliste, quiconque écrit des tests automatisés devrait avoir des compétences en développement.
Siddharth
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.