2010-07-22 3 views
2

J'essaie d'écrire un test unitaire pour une classe qui génère des chaînes distinctes. Ma première réaction a été la suivante:Unité testant une classe qui génère des chaînes distinctes

public void GeneratedStringsShouldBeDistinct() 
{ 
    UniqueStringCreator stringCreator = new UniqueStringCreator(); 
    HashSet<string> generatedStrings = new HashSet<string>(); 
    string str; 

    for (int i = 0; i < 10000; i++) 
    { 
     str = stringCreator.GetNext(); 
     if (!generatedStrings.Add(str)) 
     { 
      Assert.Fail("Generated {0} twice", str); 
     } 
    } 
} 

J'aimé cette approche parce que je savais que l'algorithme sous-jacent n'a pas utilisé tout hasard, donc je ne suis pas dans une situation où il risque d'échouer une fois, mais réussir la prochaine - mais qui pourrait être remplacé par quelqu'un dans le futur. OTOH, le test de tout algorithme aléatoire provoquerait ce type d'incohérence de test, alors pourquoi ne pas le faire de cette façon? Dois-je simplement sortir 2 éléments et vérifier la distinction (en utilisant une philosophie 0/1/Beaucoup)?

Avez-vous d'autres opinions ou suggestions?

Répondre

1

Je continuerais d'utiliser votre approche; c'est probablement l'option la plus fiable.

Par ailleurs, vous n'avez pas besoin de la déclaration if:

Assert.IsTrue(generatedStrings.Add(str), "Generated {0} twice", str); 
0

Si je voulais tester le code qui reposait sur l'entrée au hasard, je voudrais essayer de bouchonner la génération aléatoire (par exemple, ITestableRandomGenerator) pour qu'on puisse se moquer des tests. Vous pouvez ensuite injecter différentes séquences 'aléatoires' qui déclenchent de manière appropriée les différentes voies d'exécution de votre code testé et garantir la couverture de code nécessaire.

Le test particulier que vous avez montré est essentiellement un test de boîte noire, car vous générez simplement des sorties et vérifiez qu'il fonctionne pour au moins N cycles. Comme le code n'a aucune entrée, il s'agit d'un test raisonnable, bien qu'il soit préférable de savoir quelles sont les différentes conditions qui peuvent affecter votre algorithme afin de pouvoir tester ces entrées particulières. Cela peut signifier d'une manière ou d'une autre de lancer l'algorithme avec différentes valeurs de 'seed', en choisissant les graines de sorte qu'il exerce le code de différentes manières.

0

Si vous transmettez l'algorithme au constructeur de UniqueStringCreator, vous pouvez utiliser un objet stub dans votre test unitaire pour générer des données pseudo-aléatoires (prévisibles). Voir aussi le schéma de stratégie.

0

S'il y a une sorte de vérification à l'intérieur de la classe, vous pouvez toujours séparer la partie qui vérifie la distinction avec la partie qui génère les chaînes.

Puis vous simulez le vérificateur et testez le comportement dans chacun des deux contextes; celui dans lequel le vérificateur pense qu'une chaîne a été créée, et celui dans lequel elle ne l'est pas.

Vous pouvez trouver des moyens similaires de répartir les responsabilités, quelle que soit la logique d'implémentation sous-jacente.

Sinon, je suis d'accord avec SLaks - respectez ce que vous avez. La raison principale pour avoir des tests est que le code reste facile à changer, aussi longtemps que les gens peuvent le lire et penser, "Oh, c'est ce qu'il fait!" tu es probablement bon.

Questions connexes