69 votes

Tests unitaires avec les fonctions qui retournent des résultats aléatoires

Je ne pense pas que ce soit spécifique à une langue ou d'un cadre, mais je suis en utilisant xUnit.net et C#.

J'ai une fonction qui retourne une date aléatoire dans une certaine plage. Je passe dans une date, et la date de retour est toujours dans la gamme de 1 à 40 ans avant la date donnée.

Maintenant, je me demande juste si il y a un bon moyen de test de l'unité. La meilleure approche semble être de créer une boucle et laisser la fonction exécuter c'est à dire 100 fois et affirmer que chacun de ces 100 résultats sont dans la plage souhaitée, qui est mon approche actuelle.

Je me rends compte aussi que si je suis capable de contrôler mes générateur de Hasard, il n'y aura pas une solution parfaite (après tout, le résultat EST aléatoire), mais je me demande quelles sont les approches que vous prenez quand vous avez de tester les fonctionnalités qui retourne un résultat aléatoire dans une certaine plage?

55voto

Brian Genisio Points 30777

Se moquer ou faux le générateur de nombre aléatoire

Faire quelque chose comme ça... je n'ai pas le compiler alors il pourrait y avoir quelques erreurs de syntaxe.

public interface IRandomGenerator
{
    double Generate(double max);
}

public class SomethingThatUsesRandom
{
    private readonly IRandomGenerator _generator;

    private class DefaultRandom : IRandomGenerator
    {
        public double Generate(double max)
        {
            return (new Random()).Next(max);
        }
    }

    public SomethingThatUsesRandom(IRandomGenerator generator)
    {
        _generator = generator;
    }

    public SomethingThatUsesRandom() : this(new DefaultRandom())
    {}

    public double MethodThatUsesRandom()
    {
        return _generator.Generate(40.0);
    }
}

Dans votre test, il suffit de faux ou de se moquer de la IRandomGenerator de retourner quelque chose en conserve.

33voto

SquareCog Points 12947

Outre les tests de la fonction renvoie une date dans la plage souhaitée, vous voulez vous assurer que le résultat est bien répartie. Le test que vous décrivez serait de passer une fonction que simplement retourné la date que vous avez envoyé!

Donc, en plus de l'appel de la fonction plusieurs fois, et les tests que le résultat reste dans la plage souhaitée, je voudrais aussi essayer d'évaluer la distribution, peut être en mettant les résultats en seaux et en vérifiant que les seaux ont à peu près le même nombre de résultats après que vous avez terminé. Vous avez besoin de plus de 100 appels pour obtenir des résultats stables, mais cela ne ressemble pas à un coûteux (run-time sage) de la fonction, de sorte que vous pouvez facilement exécuter pour un peu de K itérations.

J'ai eu un problème avec les non-uniforme "aléatoire" fonctions.. ils peuvent être une vraie douleur, il vaut la peine de tester pour le début de l'.

9voto

Robert Rossney Points 43767

Je pense qu'il y a trois différents aspects de ce problème que vous testez.

La première: est mon algorithme le droit? C'est, compte tenu correctement fonctionnement du générateur de nombres aléatoires, il va produire des dates qui sont distribués au hasard dans la gamme?

La seconde: l'algorithme de gérer les cas de bord correctement? Par exemple, lorsque le générateur de nombre aléatoire produit de la plus haute ou la plus basse permise valeurs, n'a rien de casser?

La troisième: c'est ma mise en œuvre de l'algorithme de travail? C'est, compte tenu d'une liste connue de la pseudo-aléatoire des entrées, c'est la production attendue liste des pseudo-aléatoire dates?

Les deux premières choses ne sont pas quelque chose que j'avais à construire dans l'unité-suite de tests. Ils sont quelque chose que j'avais de prouver lors de la conception du système. Je serais probablement le faire par écrit au moyen d'un harnais de test qui a généré un tas de dates et effectué un test du chi carré, comme daniel.rikowski suggéré. Je voudrais aussi assurez-vous que ce test n'a pas arrêter jusqu'à ce qu'il s'occupait à la fois de l'arête des cas (en supposant que ma gamme de nombres aléatoires est suffisamment petite pour que je puisse sortir avec cette). Et j'avais ce document, de sorte que n'importe qui à venir et d'essayer d'améliorer l'algorithme savoir que c'est une modification de rupture.

Le dernier est quelque chose que je ferais un test unitaire pour. J'ai besoin de savoir que rien ne s'est glissée dans le code qui casse sa mise en œuvre de cet algorithme. Le premier signe je vais les faire quand cela arrive, c'est que le test échouera. Alors, je vais revenir pour le code et découvrez que quelqu'un d'autre a pensé qu'ils étaient réparer quelque chose et il s'est brisé à la place. Si quelqu'un a corrigé l'algorithme, il faudrait être sur eux pour résoudre ce test.

8voto

Ned Batchelder Points 128913

Vous n'avez pas besoin de contrôler le système afin de rendre les résultats déterministes. Vous êtes sur la bonne approche: décider de ce qui est important à propos de la sortie de la fonction et de test pour que. Dans ce cas, il est important que le résultat soit dans une gamme de 40 jours, et que vous testez. Il est également important qu'il ne retourne toujours le même résultat, donc essai pour ça aussi. Si vous voulez être plus sophistiqué, vous pouvez vérifier que les résultats passer une sorte de test aléatoire..

5voto

flolo Points 8757

Normalement j'utilise exactement votre approche suggérée: Contrôle le générateur Aléatoire. L'initialiser pour le test avec une valeur par défaut de la graine (ou de le remplacer par un proxy retour nombres qui conviennent à mon cas de tests), j'ai donc déterministe/testable comportement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X