Googler "théorie des tests de logiciels" ne semble donner que des théories au sens doux du terme; Je n'ai pas pu trouver quoi que ce soit qui puisse être qualifié de théorie au sens mathématique, théorique de l'information ou dans un autre domaine scientifique.
Ce que je recherche, c'est quelque chose qui formalise ce qu'est le test, les notions utilisées, ce qu'est un cas de test, la faisabilité de tester quelque chose, la praticité de tester quelque chose, la mesure dans laquelle quelque chose doit être testé, la définition / explication formelle de couverture du code, etc.
MISE À JOUR: De plus, je ne suis pas sûr, intuitivement, du lien entre la vérification formelle et ce que j'ai demandé, mais il y a clairement une sorte de connexion.
testing
math
theory
formal-methods
information-theory
Erik Kaplun
la source
la source
double pihole(double value) { return (value - Math.PI) / (value - Math.PI); }
que j'ai appris de mon professeur de mathématiques . Ce code a exactement un trou , qui ne peut pas être découvert automatiquement à partir des tests de boîte noire seuls. En mathématiques, ce trou n'existe pas. Dans le calcul, vous êtes autorisé à fermer le trou si les limites unilatérales sont égales.(a,b)=>a/b
, qui doit être étendue avec une valeur de dépassement, afin d'être correctement composable.Réponses:
Pour un livre explorant les mathématiques derrière les tests de logiciels ... le livre séminal à obtenir est L'Art de l'analyse des performances des systèmes informatiques: Techniques de conception expérimentale, mesure, simulation et modélisation
Bien qu'il ait été publié pour la première fois en 1991, il est toujours populaire aujourd'hui car c'est un livre de mathématiques appliquées qui se concentre uniquement sur l'analyse des performances, la simulation et les mesures.
la source
Je ne peux pas pointer vers une bonne ressource en ligne (les articles Wikipédia en anglais sur ces sujets ont tendance à être améliorables), mais je peux résumer une conférence que j'ai entendue et qui couvrait également la théorie des tests de base.
Modes de test
Il existe différentes classes de tests, comme les tests unitaires ou les tests d'intégration . Un test unitaire affirme qu'un morceau de code cohérent (fonction, classe, module) pris sur ses propres travaux comme prévu, tandis qu'un test d'intégration affirme que plusieurs de ces morceaux fonctionnent correctement ensemble.
Un cas de test est un environnement connu dans lequel un morceau de code est exécuté, par exemple en utilisant une entrée de test spécifique ou en se moquant d'autres classes. Le comportement du code est ensuite comparé au comportement attendu, par exemple une valeur de retour spécifique.
Un test ne peut que prouver la présence d'un bug, jamais l'absence de tous les bugs. Les tests mettent une limite supérieure à l'exactitude du programme.
Couverture de code
Pour définir des mesures de couverture de code, le code source peut être traduit en un graphique de flux de contrôle où chaque nœud contient un segment linéaire du code. Le contrôle circule entre ces nœuds uniquement à la fin de chaque bloc, et est toujours conditionnel (si condition, alors passez au nœud A, sinon passez au nœud B). Le graphique a un nœud de début et un nœud de fin.
Il est donc souvent utile de vérifier la couverture des conditions .
true
etfalse
. Cela implique une couverture complète des succursales, mais est plutôt coûteux. Le programme peut avoir des contraintes supplémentaires qui excluent certaines combinaisons. Cette technique est bonne pour obtenir une couverture de branche, peut trouver du code mort, mais ne peut pas trouver de bogues provenant d'une mauvaise condition.Lors de la construction d'une entrée de test à l'aide d'une couverture de condition, il convient de prendre en compte les courts-circuits. Par exemple,
doit être testé avec
foo(false, whatever)
,foo(true, false)
etfoo(true, true)
pour une couverture complète de conditions multiples minimale.Si vous avez des objets qui peuvent être dans plusieurs états, alors tester toutes les transitions d'état analogues aux flux de contrôle semble judicieux.
Il existe des mesures de couverture plus complexes, mais elles sont généralement similaires aux mesures présentées ici.
Ce sont des méthodes de test en boîte blanche et peuvent être partiellement automatisées. Notez qu'une suite de tests unitaires devrait viser à avoir une couverture de code élevée par n'importe quelle métrique choisie, mais 100% n'est pas toujours possible. Il est particulièrement difficile de tester la gestion des exceptions, où les défauts doivent être injectés dans des emplacements spécifiques.
Tests fonctionnels
Ensuite, il y a des tests fonctionnels qui affirment que le code respecte la spécification en visualisant l'implémentation comme une boîte noire. Ces tests sont utiles pour les tests unitaires et les tests d'intégration. Comme il est impossible de tester avec toutes les données d'entrée possibles (par exemple, tester la longueur de chaîne avec toutes les chaînes possibles), il est utile de regrouper l'entrée (et la sortie) en classes équivalentes - si elle
length("foo")
est correcte, elle fonctionnerafoo("bar")
probablement également. Pour chaque combinaison possible entre les classes d'équivalence d'entrée et de sortie, au moins une entrée représentative est choisie et testée.Il faut également tester
length("")
,foo("x")
,length(longer_than_INT_MAX)
,length(null)
, etlength("null byte in \x00 the middle")
…En numérique, cela signifie tester
0, ±1, ±x, MAX, MIN, ±∞, NaN
et avec des comparaisons en virgule flottante tester deux flottants voisins. Comme autre ajout, des valeurs de test aléatoires peuvent être choisies dans les classes d'équivalence. Pour faciliter le débogage, il vaut la peine d'enregistrer la graine utilisée…Tests non fonctionnels: tests de charge, tests de stress
Un logiciel a des exigences non fonctionnelles, qui doivent également être testées. Il s'agit notamment des tests aux limites définies (tests de charge) et au-delà (tests de contrainte). Pour un jeu sur ordinateur, cela pourrait être d'affirmer un nombre minimum d'images par seconde dans un test de charge. Un site Web peut être soumis à des tests de résistance pour observer les temps de réponse lorsque deux fois plus de visiteurs que prévu battent les serveurs. De tels tests ne sont pas seulement pertinents pour des systèmes entiers mais aussi pour des entités individuelles - comment une table de hachage se dégrade-t-elle avec un million d'entrées?
D'autres types de tests sont des tests de système complet dans lesquels des scénarios sont simulés, ou des tests d'acceptation pour prouver que le contrat de développement a été respecté.
Méthodes non testées
Commentaires
Il existe des techniques non testées qui peuvent être utilisées pour l'assurance qualité. Les exemples sont des procédures pas à pas, des révisions de code formelles ou la programmation de paires. Bien que certaines pièces puissent être automatisées (par exemple en utilisant des linters), elles nécessitent généralement beaucoup de temps. Cependant, les révisions de code par des programmeurs expérimentés ont un taux élevé de découverte de bogues et sont particulièrement utiles lors de la conception, où aucun test automatisé n'est possible.
Quand les revues de code sont si bonnes, pourquoi écrivons-nous toujours des tests? Le gros avantage des suites de tests est qu'elles peuvent s'exécuter (la plupart du temps) automatiquement, et sont donc très utiles pour les tests de régression .
Vérification formelle
La vérification formelle va et prouve certaines propriétés du code. La vérification manuelle est surtout viable pour les parties critiques, moins pour les programmes entiers. Les preuves mettent une limite inférieure à l'exactitude du programme. Les épreuves peuvent être automatisées dans une certaine mesure, par exemple via un vérificateur de type statique.
Certains invariants peuvent être vérifiés explicitement à l'aide d'
assert
instructions.Toutes ces techniques ont leur place et sont complémentaires. TDD écrit les tests fonctionnels à l'avance, mais les tests peuvent être jugés par leurs mesures de couverture une fois le code implémenté.
Écrire du code testable signifie écrire de petites unités de code qui peuvent être testées séparément (fonctions d'assistance avec une granularité appropriée, principe de responsabilité unique). Moins chaque fonction prend d'arguments, mieux c'est. Un tel code se prête également à l'insertion d'objets fictifs, par exemple via l'injection de dépendances.
la source
Peut-être que les "tests basés sur les spécifications" répondent également à votre question. Vérifiez ces modules de test (que je n'ai pas encore utilisés). Ils nécessitent que vous écriviez une expression mathématique pour spécifier des ensembles de valeurs de test, plutôt que d'écrire un test unitaire en utilisant des valeurs de données uniques sélectionnées.
Test :: Lectrotest
Comme le dit l'auteur, ce module Perl a été inspiré par le module de vérification rapide de Haskell . Il y a plus de liens sur cette page, dont certains sont morts.
la source
Une approche mathématique consiste à tester tous les couples . L'idée est que la plupart des bogues sont activés par un seul choix d'option de configuration, et la plupart des autres sont activés par une certaine paire d'options prises simultanément. Ainsi, la plupart peuvent être capturés en testant "toutes les paires". Une explication mathématique (avec généralisations) est ici:
Le système AETG: une approche des tests basée sur la conception combinatoire
(il existe de nombreuses autres références de ce type)
la source
Certaines équations mathématiques sont utilisées, mais cela dépend du type de test logiciel que vous utilisez. Par exemple, l' hypothèse de panne critique suppose que les pannes ne sont guère le produit de deux pannes simultanées ou plus. L'équation suivante est: f = 4n + 1. f = la fonction qui calcule le nombre de cas de test pour un nombre donné de variables ( n) + 1 est l'addition de la constante où toutes les variables prennent la valeur nominale.
Un autre type de test qui nécessite des équations mathématiques est Robustesse Test teste la robustesse ou la correction des cas de test dans un processus de test. Dans ce test, vous saisiriez des variables dans la plage d'entrée légitime (cas de test propres) et des variables d'entrée en dehors de la plage d'entrée (cas de test sales). Vous utiliseriez l'équation mathématique suivante: f = 6n + 1 . 6n indique que chaque variable doit prendre 6 valeurs différentes tandis que les autres valeurs supposent la valeur nominale. * + 1 * représente l'addition de la constante 1.
la source