65.000.000.000 tests à exécuter

50

On m'a demandé comment faire fonctionner une suite de 65.000.000.000 de tests et je me demande s'il est normal d'avoir un projet avec une telle quantité de tests.

Avez-vous travaillé dans des projets avec cette caractéristique?

juanpavergara
la source
32
65 milliards (10e9) de tests? Est-ce un problème pratique ou une question d'entrevue?
40
Je serais très intéressé de savoir qui a écrit 65 milliards de tests et combien d’années cela a pris.
Rig
46
Avec 65 milliards de tests, si vous pouvez exécuter 1 000 tests / seconde, cela prendra environ 2 ans. 10 000 tests / seconde, c'est un peu plus de deux mois. 100 000 tests / seconde prend environ une semaine. Ceci décrit une puissance de traitement importante pour exécuter les tests dans un délai raisonnable.
20
Je ne veux pas être le gars qui écrit la matrice de traçabilité ...
mouviciel
23
@DanPichelman - Il est clair que vous devez écrire un autre demi-milliard de tests pour vérifier que le générateur de tests génère correctement les tests.
Bobson

Réponses:

103

Avec 65 milliards de tests, il semble qu'on vous demande de tester toutes les entrées possibles. Ce n'est pas utile - vous allez essentiellement vérifier que votre processeur fonctionne correctement, mais que votre code est correct.

Vous devriez plutôt tester les classes d'équivalence . Cela réduira considérablement votre gamme d'entrées de test.

Déterminez également si vous pouvez subdiviser votre système en éléments plus petits. Chaque pièce sera plus facile à tester isolément, et vous pourrez ensuite effectuer des tests d'intégration qui réuniront toutes les pièces.

Si vous souhaitez toujours avoir l'assurance que certaines de ces combinaisons d'entrées fonctionnent, vous pouvez peut-être essayer le test fuzz . Vous obtiendrez certains des avantages de tester de nombreux intrants différents, mais sans en exécuter 65 milliards.

M. Dudley
la source
12
+1, surtout pour "vous allez essentiellement vérifier que votre processeur fonctionne correctement"
Doc Brown
4
Pour les fonctions assez simples (peu tripoter etc.) Je ne tends à tester toutes les valeurs possibles. C'est infaillible et me donne donc une bien meilleure confiance que de tester des classes d'équivalence (dérivées et donc potentiellement erronées). Bien sûr, cela ne fonctionne plus lorsque vos entrées potentielles se chiffrent en milliards.
Konrad Rudolph
39

S'il s'agit d'une vraie suite de tests, vous ne voudrez pas travailler dessus.

Tout le travail d'un testeur consiste à trouver un équilibre entre des tests suffisamment approfondis pour être sûr que vous obtenez les "bons" résultats et écrire assez de tests pour pouvoir les exécuter dans un délai raisonnable.

De nombreux tests peuvent être résumés en "classes d'équivalence", ce qui signifie qu'au lieu d'exécuter 3 milliards de tests, vous en exécutez 1 qui vous donne un niveau de confiance raisonnable quant à l'exécution de tous les autres tests de cette classe d'équivalence, si vous décidiez de gaspiller les ressources. le temps de les courir.

Vous devez indiquer à ceux qui envisagent de réaliser 65 milliards de tests qu’ils ont besoin de faire un meilleur travail pour résumer les tests en classes d’équivalence.

dsw88
la source
+1 sur des tests approfondis mais efficaces.
Marco
23

Plus que probablement, vous êtes parvenu à votre chiffre de 65 milliards de tests en calculant toutes les combinaisons possibles d'entrées dans le système testé, ou en calculant la complexité cyclomatique en supposant qu'un test doit être écrit pour chacun de ces chemins d'exécution uniques.

Ce n’est pas ainsi que sont écrits les vrais tests car, comme d’autres affiches et commentateurs l’ont indiqué, le pouvoir technique nécessaire pour exécuter 65 milliards de dollarsles tests sont stupéfiants. Ce serait comme écrire un test qui utilise une méthode pour ajouter deux nombres entiers en insérant toutes les permutations possibles de deux valeurs 32 bits et en vérifiant le résultat. C'est la folie totale. Vous devez tracer la ligne et identifier un sous-ensemble de tous les tests élémentaires possibles, ce qui garantirait que le système se comportera comme prévu tout au long de la plage d'entrées. Par exemple. vous testez en ajoutant quelques nombres "ordinaires", vous testez quelques scénarios de nombres négatifs, vous testez des limites techniques telles que des scénarios de dépassement de capacité et vous testez tous les scénarios susceptibles de générer une erreur. Comme il a été mentionné, ces différents types de tests exercent des "classes d'équivalence"; ils vous permettent de prendre un échantillon représentatif des entrées possibles, ainsi que de tous les "points aberrants" connus,

Prenons l’un des katas de code de base, le générateur de chiffres romains. La tâche, à exécuter à l'aide de techniques TDD dans un style "dojo", consiste à écrire une fonction pouvant accepter n'importe quel nombre compris entre 1 et 3 000 et générer le nombre correct de chiffres romains pour cette valeur numérique.

Vous ne résolvez pas ce problème en écrivant 3000 tests unitaires, un à la fois, et en les passant à tour de rôle. C'est de la folie. l'exercice prend normalement entre une et deux heures et vous seriez là pendant des jours pour tester chaque valeur individuelle. Au lieu de cela, vous devenez intelligent. Vous commencez par le cas de base le plus simple (1 == "I"), implémentez-le à l'aide d'une stratégie "moindre code" ( return "I";), puis recherchez le comportement incorrect de votre code dans un autre scénario attendu (2 == " II "). Rincer et répéter; Plus que probablement, vous avez remplacé votre implémentation initiale par quelque chose qui répète le caractère "I" aussi souvent que nécessaire (comme return new String('I',number);). Cela passera évidemment un test pour III, alors vous ne vous inquiétez pas; à la place, vous écrivez le test pour 4 == "IV", dont vous connaissez la mise en oeuvre actuelle gagnée '

Ou, dans un style plus analytique, vous examinez chaque décision conditionnelle prise par le code (ou doit l'être) et écrivez un test conçu pour saisir le code correspondant à chaque résultat possible de chaque décision. Si vous avez 5 instructions if (chacune ayant une branche vraie et une branche fausse), chacune d'entre elles étant totalement indépendantes les unes des autres, vous codez 10 tests, et non 32. Chaque test sera conçu pour affirmer deux choses à propos d'une décision possible particulière; tout d'abord que la décision correcte est prise, puis que le code saisi en fonction de cette condition est correct. Vous ne codez pas de test pour chaque permutation possible de décisions indépendantes. Si les décisions sont dépendantes, vous devez en tester plusieurs en combinaison, mais elles sont moins nombreuses car certaines décisions ne sont jamais prises que lorsqu'une autre décision a eu un résultat particulier.

KeithS
la source
5

Est-ce "normal" ?, non. Où "normal" est défini comme l'expérience moyenne ou typique. Je ne peux pas dire que j’ai déjà eu à travailler sur un projet de ce type, mais j’ai travaillé sur un projet dans lequel un bit sur quelques millions serait inversé. Tester celui-là était ... un défi.

Est-ce potentiellement nécessaire? Cela dépend des garanties et des spécificités du projet. C'est un peu incrédule à comprendre au début, mais votre question est claire.

Comme d'autres (MichaelT) l'ont souligné, le temps nécessaire pour effectuer cette tâche avec des tests en série rend cette tâche peu pratique. Donc, la parallélisation devient votre première considération. Combien de systèmes de test pouvez-vous résoudre ce problème et quel soutien avez-vous pour rassembler les résultats de ces systèmes multiples?

Quelles garanties avez-vous que le périphérique ou l'algorithme que vous testez est répliqué de manière fiable? Les logiciels sont assez fiables pour la réplication, mais les périphériques matériels (en particulier ceux de première génération) peuvent poser des problèmes de fabrication. Un échec de test faux dans ce cas pourrait indiquer un algorithme incorrect ou le périphérique ne s'est pas assemblé correctement. Avez-vous besoin de faire la distinction entre ces deux cas?

Vous devrez également déterminer comment vous allez valider les systèmes de test eux-mêmes. En supposant une raison légitime pour de nombreux tests, vous aurez besoin de beaucoup d’automatisation. Cette automatisation doit être inspectée pour s'assurer qu'elle ne commet pas une erreur en générant vos scénarios de test. Des vérifications ponctuelles d'erreurs seraient vraiment l'équivalent de trouver une aiguille dans une botte de foin.

Ce lien arstechnica peut apporter ou non des éclaircissements sur vos considérations en matière de test. Les clusters GPU sont couramment utilisés pour les mots de passe de cracking force. Celui cité dans l'article le peut can cycle through as many as 350 billion guesses per second, alors cela met en quelque sorte vos tests 65B. C'est probablement un domaine différent, mais cela montre comment aborder la tâche sous différents angles peut donner une solution viable.


la source
3

Je ne pense pas qu'il soit possible de maintenir 6.5e + 10 tests en premier lieu, donc les lancer peut être discutable. Même les plus gros projets, comme Debian avec tous ses paquets, ne totalisent que plusieurs centaines de millions de SLOC.

Mais si vous devez quand même effectuer un grand nombre de tests, il existe quelques stratégies.

  • Ne les lancez pas tous. Très probablement, tous les tests ne dépendent pas de chaque chemin de code. Définissez les dépendances entre les sous-systèmes et leurs tests, et entre les suites de tests, et vous ne pourrez exécuter que des tests unitaires correspondant à une modification donnée, uniquement les tests d'intégration en fonction de ces tests unitaires, etc.

  • Exécutez-les en parallèle. Avec une base de code aussi énorme, vous avez probablement une ferme de construction massive (de retour chez JetBrains, une entreprise relativement petite, nous avions auparavant 40 à 50 agents de compilation exécutés uniquement sur la ferme de construction / intégration continue IDEA). Comme les tests unitaires sont indépendants et que les tests d'intégration peuvent réutiliser le code déjà construit, les tests sont relativement faciles à paralléliser.

  • Arrêtez de courir tôt. Si vous savez qu'une suite de tests particulière dépend, pour son bon fonctionnement, de l'exactitude d'une autre suite de tests, vous pouvez couper toute la chaîne dès qu'un lien échoue.

Avertissement: je ne suis pas un ingénieur de test professionnel. Prenez ce qui précède avec un grain de sel.

9000
la source
5
... Bien sûr, chez JetBrains, ces agents de build sont gratuits car ils développent TeamCity et en sont les propriétaires. D'autres "opérations relativement petites" auraient probablement une crise cardiaque en pensant à un coût initial d'environ 15 000 dollars (juste pour le logiciel; ajoutez 40 à 50 unités blademount et autres matériels, et même en utilisant une distribution Linux gratuite pour l'héberger à votre guise. Nous parlons facilement du salaire annuel d'un développeur senior) et de 6 500 USD de frais de maintenance annuels, auxquels s'ajoutent le temps et les compétences du personnel informatique nécessaire pour faire en sorte que la ferme de construction continue de fonctionner.
KeithS
0

Bien qu'il y ait eu plusieurs bonnes suggestions ici sur la façon d'essayer de se faufiler avec moins de tests, je doute sérieusement que votre système ne comporte que 65 milliards de combinaisons d'entrées. C'est moins de 36 bits d'entrée. Supposons que vous avez déjà suivi tous les conseils donnés ci-dessus.

Si chaque test prend environ une milliseconde à exécuter et que vous distribuez les tests sur seulement 10 processeurs (un PC normal), le test s'exécute en un peu plus de 69 jours. C'est un moment, mais pas complètement déraisonnable. Distribuez sur 100 processeurs (une douzaine de PC normaux ou un PC serveur raisonnable) et les tests seront terminés en moins de 7 jours. Vous pouvez les exécuter chaque semaine pour vérifier les régressions.

Paul Scherf
la source