Les assertions et les tests unitaires servent à la fois de documentation pour une base de code et de moyen de détecter les bogues. Les principales différences sont que les assertions fonctionnent comme des contrôles de cohérence et voient les entrées réelles, alors que les tests unitaires fonctionnent sur des entrées simulées spécifiques et sont des tests par rapport à une "bonne réponse" unique et bien définie. Quels sont les avantages relatifs de l'utilisation d'assertions par rapport à des tests unitaires comme principal moyen de vérifier l'exactitude? Selon vous, sur lequel devrait-on insister plus lourdement?
testing
unit-testing
assertions
Dsimcha
la source
la source
:-)
Réponses:
Les assertions sont utiles pour vous informer de l'état interne du programme . Par exemple, vos structures de données ont un état valide, par exemple, une
Time
structure de données ne tiendra pas la valeur de25:61:61
. Les conditions vérifiées par les assertions sont les suivantes:Conditions préalables, qui assurent que l'appelant respecte son contrat,
Postconditions, qui assure que l'appelé respecte son contrat, et
Les invariants, qui assurent que la structure de données contient toujours une propriété après le retour de la fonction. Un invariant est une condition qui est une condition préalable et une condition ultérieure.
Les tests unitaires sont utiles pour vous informer sur le comportement externe du module . Vous
Stack
pouvez avoir un état cohérent après l'push()
appel de la méthode, mais si la taille de la pile n'augmente pas de trois après l'appel de trois fois, il s'agit d'une erreur. (Par exemple, le cas trivial où l'push()
implémentation incorrecte vérifie uniquement les assertions et se termine.)Strictement parlant, la principale différence entre les assertions et les tests unitaires réside dans le fait que les tests unitaires contiennent des données de test (valeurs permettant au programme de s'exécuter), contrairement aux assertions. Autrement dit, vous pouvez exécuter vos tests unitaires automatiquement, alors que vous ne pouvez pas en dire autant pour les assertions. Pour les besoins de cette discussion, j'ai supposé que vous parliez de l'exécution du programme dans le contexte des tests de fonction d'ordre supérieur (qui exécutent l'ensemble du programme et ne pilotent pas les modules comme les tests unitaires). Si vous ne parlez pas de tests de fonction automatisés comme moyen de "voir les entrées réelles", alors clairement l'intérêt de l'automatisation réside dans le succès des tests unitaires. Si vous en parlez dans le cadre de tests de fonctions (automatisés), reportez-vous à la section ci-dessous.
Il peut y avoir un certain chevauchement dans ce qui est testé. Par exemple,
Stack
la postcondition de a peut en fait affirmer que la taille de la pile augmente de un. Mais il y a des limites à ce qui peut être fait dans cette affirmation: faut-il aussi vérifier que l'élément supérieur est ce qui vient d'être ajouté?Pour les deux, l'objectif est d'améliorer la qualité. Pour les tests unitaires, l'objectif est de trouver des bogues. Pour les assertions, l'objectif est de faciliter le débogage en observant les états de programme non valides dès qu'ils se produisent.
Notez que ni l'une ni l'autre technique ne vérifie l'exactitude. En fait, si vous effectuez des tests unitaires dans le but de vérifier que le programme est correct, vous obtiendrez probablement un test sans intérêt qui, à votre connaissance, fonctionnera. C'est un effet psychologique: vous ferez tout ce qui est en votre pouvoir pour atteindre votre objectif. Si votre objectif est de trouver des bugs, vos activités le refléteront.
Les deux sont importants et ont leurs propres objectifs.
[Note finale sur les assertions: pour obtenir le maximum de valeur, vous devez les utiliser à tous les points critiques de votre programme, et non à quelques fonctions clés. Sinon, la source du problème d'origine aurait peut-être été masquée et difficile à détecter sans des heures de débogage.]
la source
Lorsque vous parlez d'assertions, gardez à l'esprit qu'elles peuvent être désactivées sur simple pression d'un commutateur.
Exemple d'une très mauvaise assertion:
Pourquoi est-ce mauvais? Parce qu'aucune vérification d'erreur n'est effectuée si cette assertion est ignorée en raison de la définition de NDEBUG.
Un test unitaire serait (probablement) juste une erreur de segmentation sur le code ci-dessus. Bien sûr, il a fait son travail en vous disant que quelque chose ne va pas, ou l'a-t-il fait? Quelle est la probabilité
malloc()
d'échec sous le test?Les assertions sont à des fins de débogage lorsqu'un programmeur doit impliquer qu'aucun événement «normal» ne déclencherait l'assertion.
malloc()
échouer est, en effet, un événement normal, donc ne devrait jamais être affirmé.Il existe de nombreux autres cas dans lesquels des assertions sont utilisées au lieu de traiter correctement des problèmes pouvant aller mal. C'est pourquoi les assertions ont mauvaise réputation et que des langues telles que Go ne les incluent pas.
Les tests unitaires sont conçus pour vous avertir lorsque quelque chose que vous avez modifié a cassé autre chose. Ils sont conçus pour vous éviter (dans la plupart des cas) de parcourir toutes les fonctionnalités du programme (les testeurs sont toutefois importants pour les versions) à chaque fois que vous effectuez une construction.
Il n'y a pas vraiment de corrélation distincte entre les deux, si ce n'est qu'ils vous ont tous deux dit que quelque chose s'était mal passé. Pensez à une assertion comme un point d'arrêt dans quelque chose sur lequel vous travaillez, sans avoir à utiliser un débogueur. Pensez à un test unitaire comme quelque chose qui vous dit si vous avez cassé quelque chose sur lequel vous ne travaillez pas .
la source
Ce sont deux outils utilisés pour améliorer la qualité globale du système que vous construisez. Cela dépend beaucoup de la langue que vous utilisez, du type d'application que vous construisez et du meilleur endroit où vous passerez votre temps. Sans compter que vous avez quelques écoles de pensée à ce sujet.
Pour commencer, si vous utilisez une langue sans
assert
mot-clé, vous ne pouvez pas utiliser d'assertions (du moins pas comme nous parlons ici). Pendant longtemps, Java n’avait pas deassert
mot-clé et de nombreuses langues n’en avaient toujours pas. Les tests unitaires deviennent alors un peu plus importants. Dans certaines langues, les assertions ne sont exécutées que lorsqu'un indicateur est défini (ici encore avec Java). Lorsque les protections ne sont pas toujours là, ce n'est pas une fonctionnalité très utile.Il existe une école de pensée qui dit que si vous "affirmez" quelque chose, vous pourriez aussi bien écrire un bloc d'exception
if
/throw
significatif. Ce processus de pensée provient de nombreuses assertions placées au début d'une méthode pour s'assurer que toutes les valeurs sont dans des limites. Tester vos conditions préalables est une partie très importante de la postcondition attendue.Le test unitaire est un code supplémentaire qui doit être écrit et maintenu. Pour beaucoup, c'est un inconvénient. Cependant, avec la série actuelle de frameworks de tests unitaires, vous pouvez générer un plus grand nombre de conditions de test avec relativement peu de code. Les tests paramétrés et les "théories" effectueront le même test avec un grand nombre d'échantillons de données pouvant révéler des bogues difficiles à trouver.
Personnellement, je trouve que les tests unitaires me permettent de gagner plus de temps que de parler de saupoudrage, mais cela est dû aux plates-formes que je développe la plupart du temps (Java / C #). D'autres langues ont un support d'assertion plus robuste, et même "Conception par contrat" (voir ci-dessous) pour offrir encore plus de garanties. Si je travaillais avec l'une de ces langues, je pourrais utiliser davantage le DBC que les tests unitaires.
http://en.wikipedia.org/wiki/Design_by_contract#Languages_with_native_support
la source