Les tests unitaires automatisés peuvent-ils remplacer la vérification de type statique?

StackOverflow https://stackoverflow.com/questions/415434

  •  03-07-2019
  •  | 
  •  

Question

J'ai commencé à examiner toute l'idée de développement basé sur les tests unitaires / pilotés par les tests, et plus j'y réfléchis, plus elle semble jouer un rôle similaire à celui de la vérification de type statique. Les deux techniques permettent une vérification rapide, au moment de la compilation, de certains types d’erreurs dans votre programme. Cependant, corrigez-moi si je me trompe, mais il semble qu'une suite de tests unitaires avec une couverture complète teste tout ce que la vérification de type statique doit tester, puis certains. Autrement dit, les vérifications de type statique ne font qu'une partie du chemin pour & «Prouver &»; que votre programme est correct, alors que les tests unitaires vous permettront & de prouver & "; autant que vous voulez (dans une certaine mesure).

Alors, y a-t-il une raison d'utiliser une langue avec la vérification de type statique si vous utilisez également le test unitaire? ici , une question un peu similaire a été posée, mais j'aimerais entrer dans les détails. . Quels sont les avantages spécifiques éventuels de la vérification de type statique par rapport aux tests unitaires? Quelques problèmes comme l'optimisation du compilateur et intellisense me viennent à l'esprit, mais existe-t-il d'autres solutions à ces problèmes? Y a-t-il d'autres avantages / inconvénients auxquels je n'ai pas pensé?

Était-ce utile?

La solution

Je pense que les tests unitaires automatisés seront importants pour les langages typés dynamiques, mais cela ne signifie pas qu'ils remplaceraient la vérification de type statique dans le contexte que vous appliquez. En fait, certains utilisateurs du typage dynamique l’utilisent peut-être parce qu’ils ne veulent pas avoir le souci des tracas liés aux contrôles de sécurité de type constant.

Les avantages des langages à typage dynamique par rapport aux langages à typage statique vont bien au-delà des tests et la sécurité des types n’est qu’un aspect. Les styles de programmation et les différences de conception par rapport aux langages dynamiques et statiques varient également considérablement.

De plus, les tests unitaires écrits de manière trop stricte pour garantir la sécurité de type signifieraient que le logiciel ne devrait finalement pas être typé de manière dynamique, ou que la conception appliquée soit écrite dans un langage à typage statique, et non dynamique.

Autres conseils

Il existe un fait immuable concernant la qualité du logiciel.

  

S'il ne peut pas compiler, il ne peut pas être expédié

Dans cette règle, les langages à typage statique l'emporteront sur les langages à typage dynamique.

Ok, oui cette règle n'est pas immuable. Les applications Web peuvent être livrées sans compilation (j'ai déployé de nombreuses applications Web de test qui ne compilaient pas). Mais ce qui est fondamentalement vrai est

  

Plus tôt une erreur est détectée, moins il est facile de la réparer

Un langage à typage statique empêchera que de vraies erreurs se produisent à l’un des moments les plus précoces du cycle de développement du logiciel. Un langage dynamique ne sera pas. Les tests unitaires, si vous êtes approfondis à un niveau surhumain, peuvent remplacer un langage à typage statique.

Cependant, pourquoi s'embêter? Il y a beaucoup de gens incroyablement intelligents qui écrivent pour vous un système complet de vérification d'erreur sous la forme d'un compilateur. Si vous souhaitez obtenir des erreurs plus rapidement, utilisez un langage de type statique.

Ne considérez pas ce message comme un dénigrement de langages dynamiques. J'utilise des langages dynamiques tous les jours et je les aime. Ils sont incroyablement expressifs et flexibles et permettent des programmes incroyablement fanscinants. Cependant, dans le cas de rapports d’erreurs précoces, ils sont perdus au profit de langages statiques.

Pour tout projet de taille raisonnable, vous ne pouvez pas prendre en compte toutes les situations avec des tests unitaires uniquement.

Donc, ma réponse est & "non &"; et même si vous parveniez à rendre compte de toutes les situations, vous avez de ce fait renoncé à utiliser un langage dynamique.

Si vous souhaitez programmer en fonction du type, utilisez plutôt un langage compatible avec le type.

Avoir 100% de couverture de code ne signifie pas que vous avez entièrement testé votre application. Considérez le code suivant:

if (qty > 3)
{
    applyShippingDiscount();
}
else
{
    chargeFullAmountForShipping();
}

Je peux obtenir 100% de couverture de code si je pompe dans les valeurs de qty = 1 et qty = 4.

Maintenant, imaginez mon état d'affaires était que quot &, ... pour les commandes de 3 ou plus d'articles que je suis d'appliquer une réduction des frais d'expédition .. quot ;. & Ensuite, je aurais besoin d'écrire des tests qui ont travaillé sur les limites. Donc, je concevais des tests où qty était de 2,3 et 4. J'ai toujours une couverture de 100% mais, plus important, j'ai trouvé un bug dans ma logique.

Et c'est le problème que j'ai avec mettant l'accent sur la couverture de code seul. Je pense que, au mieux, vous vous retrouvez avec une situation où le développeur crée des tests initiaux sur la base des règles métier. Ensuite, afin de conduire le nombre de couverture auxquels ils font référence leur code lors de la conception de nouveaux cas de test.

Le typage de manifeste (ce que je suppose que vous voulez dire) est une forme de spécification, le test unitaire est beaucoup plus faible puisqu'il ne fournit que des exemples. La différence importante est qu’une spécification déclare ce qui doit être respecté dans tous les cas, alors qu’un test ne couvre que des exemples. Vous ne pouvez jamais être sûr que vos tests couvrent toutes les conditions aux limites.

Les gens ont également tendance à oublier la valeur des types déclarés en tant que documentation. Par exemple, si une méthode Java retourne un List<String>, je sais instantanément ce que je reçois, inutile de lire la documentation, les scénarios de test ou même le code de la méthode elle-même. De même pour les paramètres: si le type est déclaré, alors je sais ce que la méthode attend.

La valeur de la déclaration du type des variables locales est beaucoup plus faible car, dans un code bien écrit, la portée de la variable devrait être réduite. Vous pouvez toujours utiliser le typage statique, cependant: au lieu de déclarer le type, vous laissez le compilateur l'inférer. Des langues telles que Scala ou même C # vous permet de le faire.

Certains styles de test se rapprochent d'une spécification, par exemple. QuickCheck ou sa variante Scala ScalaCheck génèrent des tests basés sur des spécifications, en essayant de deviner les limites importantes.

Je formulerais les choses autrement - si vous ne possédez pas de langage à typage statique, vous devez mieux passer des tests unitaires très complets si vous envisagez de faire quoi que ce soit & ";" réel " avec ce code.

Cela dit, le typage statique (ou plutôt le typage explicite) présente des avantages significatifs par rapport aux tests unitaires, ce qui me permet de le préférer de manière générale. Il crée des API beaucoup plus compréhensibles et permet de visualiser rapidement le & "Squelette &"; d’une application (c’est-à-dire que l’entrée pointe sur chaque module ou section de code) de manière beaucoup plus difficile avec un langage à typage dynamique.

Pour résumer: à mon avis, avec des tests unitaires rigoureux et approfondis, le choix entre un langage à typage dynamique et un langage à typage statique est principalement un choix de goût. Certaines personnes préfèrent un; d'autres préfèrent l'autre. Utilisez le bon outil pour le travail. Mais cela ne signifie pas pour autant qu'ils sont identiques: les langages à typage statique auront toujours un avantage d'une certaine manière, et les langages à typage dynamique auront toujours un avantage de différentes manières. Les tests unitaires contribuent dans une large mesure à minimiser les inconvénients des langages à typage dynamique, mais ils ne les éliminent pas complètement.

Non.

Mais ce n'est pas la question la plus importante, la question la plus importante est: est-ce important que cela ne soit pas possible?

Considérons le but de la vérification de type statique: éviter une classe de défauts de code (bugs). Cependant, ceci doit être pesé dans le contexte du domaine plus large de tous les défauts de code. Ce qui importe le plus n’est pas une comparaison sur une bande étroite, mais une comparaison de la profondeur et de l’ampleur de la qualité du code, de la facilité avec laquelle il est possible d’écrire un code correct, etc. Si vous pouvez proposer un style / processus de développement permettant à votre équipe de produire une qualité supérieure code plus efficacement sans vérification de type statique, alors ça vaut le coup. Cela est vrai même dans le cas où vos tests comportent des lacunes que la vérification de type statique corrigerait.

Je suppose que cela pourrait être le cas si vous êtes très complet. Mais pourquoi s'embêter? Si la langue vérifie déjà que les types statiques sont corrects, il ne servirait à rien de les tester (puisque vous les obtenez gratuitement).

De même, si vous utilisez des langages à typage statique avec un IDE, celui-ci peut vous fournir des erreurs et des avertissements, même avant la compilation pour le test. Je ne suis pas certain qu'il existe des applications de tests unitaires automatisées capables de faire de même.

Compte tenu de tous les avantages des langages dynamiques à liaison tardive, je suppose que cela fait partie des valeurs offertes par les tests unitaires. Vous aurez toujours besoin de coder avec soin et intentionnellement, mais c'est la condition n ° 1 pour tout type de codage à mon humble avis. Etre capable de rédiger des tests clairs et simples aide à prouver la clarté et la simplicité de votre conception et de votre mise en œuvre. Il fournit également des indices utiles pour ceux qui verront votre code plus tard. Mais je ne pense pas que je compte sur elle pour détecter les types incompatibles. Mais dans la pratique, je ne trouve pas que la vérification de type détecte de nombreuses erreurs réelles de toute façon. Ce n’est tout simplement pas un type d’erreur que je trouve se produisant dans du code réel, si vous avez un style de codage clair et simple au départ.

Pour javascript, jsLint trouverait presque tous les problèmes de vérification de type. principalement en suggérant d’autres styles de codage pour diminuer votre exposition.

La vérification de type aide à appliquer des contrats entre les composants d'un système. Les tests unitaires (comme leur nom l’indique) vérifient la logique interne des composants.

Pour une seule unité de code, je pense que les tests unitaires peuvent réellement rendre inutile la vérification de type statique. Mais dans un système complexe, les tests automatisés ne peuvent pas vérifier toutes les nombreuses façons dont les différents composants du système peuvent interagir. Pour cela, l'utilisation des interfaces (qui sont en quelque sorte une sorte de & Quot; contrat & "; Composants) devient un outil utile pour réduire les erreurs potentielles. Et les interfaces nécessitent une vérification de type à la compilation.

J'aime beaucoup programmer en langage dynamique, donc je ne dénigre certainement pas le typage dynamique. C'est juste un problème qui m'est récemment arrivé. Malheureusement, je n'ai pas vraiment d'expérience dans l'utilisation d'un langage dynamique pour un système vaste et complexe. Je serais donc intéressé de savoir si ce problème est réel ou simplement théorique.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top