Testy jednostkowe z funkcjami zwracającymi losowe wyniki

Nie wydaje mi się, aby było to specyficzne dla języka czy frameworka, ale używam xUnit.net i C#.

Mam funkcję, która zwraca losową datę w określonym przedziale. Zdaję datę, a data powrotu jest zawsze w zakresie od 1 do 40 lat przed podaną datą.

Teraz zastanawiam się, czy jest dobry sposób, aby to przetestować. Najlepszym podejściem wydaje się stworzenie pętli i niech funkcja działa tj. 100 razy i twierdzenie, że każdy z tych 100 wyników jest w pożądany zasięg, czyli moje obecne podejście.

Zdaję sobie również sprawę, że jeśli nie będę w stanie kontrolować mojego generatora losowego, nie będzie idealnego rozwiązania (w końcu wynik jest losowy), ale zastanawiam się, jakie podejście bierzesz, gdy musisz przetestować funkcjonalność, która zwraca losowy wynik w określonym zakresie?

Author: Michael Stum, 2008-11-23

11 answers

Oprócz sprawdzania, czy funkcja zwraca datę w żądanym zakresie, chcesz upewnić się, że wynik jest dobrze rozłożony. Test, który opisujesz, przejdzie przez funkcję, która po prostu zwróci datę wysłania!

Więc oprócz wielokrotnego wywoływania funkcji i sprawdzania, czy wynik pozostaje w pożądanym zakresie, chciałbym również spróbować ocenić rozkład, być może umieszczając wyniki w wiadrach i sprawdzając, czy wiadra mają mniej więcej równe liczby wyniki po zakończeniu. Możesz potrzebować więcej niż 100 wywołań, aby uzyskać stabilne wyniki, ale to nie brzmi jak kosztowna (pod względem czasu działania) Funkcja, więc możesz ją łatwo uruchomić przez kilka iteracji K.

Miałem już problem z niejednolitymi funkcjami "losowymi".. mogą być prawdziwym bólem, warto wcześniej przetestować.

 31
Author: SquareCog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-31 06:37:43

Wymyśl lub sfałszuj generator liczb losowych

Zrób coś takiego... Nie skompilowałem go, więc może być kilka błędów składniowych.
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);
    }
}

W Twoim teście, po prostu udawaj lub wyśmiewaj IRandomGenerator, aby zwrócić coś w puszkach.

 49
Author: Brian Genisio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-22 21:54:58

Myślę, że są trzy różne aspekty tego problemu, które testujesz.

Pierwszy: czy mój algorytm jest właściwy? Oznacza to, że biorąc pod uwagę prawidłowo działający generator liczb losowych, będzie produkować daty, które są losowo rozmieszczone w całym zakresie?

Druga: czy algorytm poprawnie obsługuje przypadki edge ' a? Oznacza to, że gdy generator liczb losowych wytwarza najwyższe lub najniższe dopuszczalne wartości, czy coś się łamie?

Trzeci: czy mój implementacja algorytmu działa? Oznacza to, że biorąc pod uwagę znaną listę pseudolosowych wejść, czy produkuje oczekiwaną listę pseudolosowych dat?

Pierwsze dwie rzeczy nie są czymś, co wbudowałbym w zestaw testów jednostkowych. To coś, co udowodniłbym podczas projektowania systemu. Prawdopodobnie zrobiłbym to, pisząc uprząż testową, która generowała miliony dat i wykonywała test chi-kwadrat, jako daniel.zasugerował: rikowski Upewniłbym się również, że ta uprząż testowa nie zostanie przerwana dopóki nie obsłuży obu przypadków krawędzi (zakładając, że mój zakres liczb losowych jest na tyle mały, że mogę uciec z tego). I udokumentowałbym to, żeby każdy, kto przyjdzie i spróbuje poprawić algorytm, wiedział, że to przełomowa zmiana.

Ostatni to coś, dla czego zrobiłbym test jednostkowy. Muszę wiedzieć, że do kodu nie wkradło się nic, co łamie jego implementację tego algorytmu. Pierwszy znak, jaki dostanę, gdy tak się stanie, to że test zawiedzie. Potem wrócę do kodu i dowiem się, że ktoś inny myślał, że coś naprawia i go złamał. Jeśli ktoś zrobił naprawienie algorytmu, to na nim będzie również naprawienie tego testu.

 9
Author: Robert Rossney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-23 01:41:54

Nie musisz kontrolować systemu, aby wyniki były deterministyczne. Jesteś na właściwym podejściu: zdecyduj, co jest ważne w wyjściu funkcji i przetestuj to. W takim przypadku ważne jest, aby wynik był w zakresie 40 dni, a Ty testujesz na to. Ważne jest również, aby nie zawsze zwracał ten sam wynik, więc przetestuj również to. Jeśli chcesz być bardziej fantazyjny, możesz sprawdzić, czy wyniki przechodzą jakiś test losowości..

 8
Author: Ned Batchelder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-22 21:45:21

Normalnie używam dokładnie Twojego sugerowanego podejścia: Kontroluj generator losowy. Zainicjalizuj go do testu domyślnym zalążkiem (lub zastąp go proxy zwracającym liczby pasujące do moich testów), więc mam deterministyczne / testowalne zachowanie.

 5
Author: flolo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-22 21:43:18

Jeśli chcesz sprawdzić jakość liczb losowych (pod względem niezależności), można to zrobić na kilka sposobów. Dobrym sposobem jest test chi kwadrat .

 4
Author: Daniel Rikowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-22 21:52:33

W zależności od tego, jak twoja funkcja tworzy losową datę, Możesz również sprawdzić nielegalne daty: niemożliwe lata przestępne lub 31 dzień 30-dniowego miesiąca.

 2
Author: mseery,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-23 01:50:30

Metody, które nie wykazują deterministycznego zachowania, nie mogą być właściwie testowane jednostkowo, ponieważ wyniki będą się różnić w zależności od wykonania. Jednym ze sposobów na obejście tego jest seed generator liczb losowych o stałej wartości dla testu jednostkowego. Można również wyodrębnić losowość klasy generowania daty (a tym samym zastosować zasadę pojedynczej odpowiedzialności ) i wprowadzić znane wartości dla testów jednostkowych.

 2
Author: philant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-11 12:37:53

Jasne, użycie generatora liczb losowych ze stałymi nasionami będzie działać dobrze, ale nawet wtedy po prostu próbujesz przetestować to, czego nie możesz przewidzieć. Co jest ok. To jest równoznaczne z kilkoma stałymi testami. Pamiętajcie jednak-testujcie to, co ważne, ale nie próbujcie wszystkiego testować. Uważam, że testy losowe są sposobem na próbę przetestowania wszystkiego, a to nie jest skuteczne (lub szybkie). Potencjalnie musisz przeprowadzić wiele randomizowanych testów przed trafieniem w błąd.

What I ' m próba dotarcia do tego jest taka, że powinieneś po prostu napisać test dla każdego błędu, który znajdziesz w systemie. Testujesz przypadki edge, aby upewnić się, że twoja funkcja działa nawet w ekstremalnych warunkach, ale tak naprawdę to najlepsze, co możesz zrobić, nie spędzając zbyt dużo czasu lub spowalniając testy jednostkowe lub po prostu marnując cykle procesora.

 2
Author: thekingoftruth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-29 17:51:23

Zalecałbym nadpisanie funkcji losowej. Testuję w PHP więc piszę ten kod:

// If we are unit testing, then...
if (defined('UNIT_TESTING') && UNIT_TESTING)
{
   // ...make our my_rand() function deterministic to aid testing.
   function my_rand($min, $max)
   {
      return $GLOBALS['random_table'][$min][$max];
   }
}
else
{
   // ...else make our my_rand() function truly random.
   function my_rand($min = 0, $max = PHP_INT_MAX)
   {
      if ($max === PHP_INT_MAX)
      {
         $max = getrandmax();
      }
      return rand($min, $max);
   }
}

Następnie ustawiam random_table, ponieważ wymagam tego na test.

Testowanie rzeczywistej losowości funkcji losowej jest całkowicie oddzielnym testem. Unikałbym testowania losowości w testach jednostkowych i zamiast tego robiłbym oddzielne testy i wygooglował prawdziwą losowość funkcji losowej w języku programowania, którego używasz. Badania niedeterministyczne (jeśli w ogóle) należy pominąć testy jednostkowe. Może mieć osobny zestaw do tych testów, które wymagają ludzkiego wkładu lub znacznie dłuższych czasów pracy, aby zminimalizować szanse na porażkę, która jest naprawdę pass.
 1
Author: user263976,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-02 01:01:10

Nie sądzę, żeby testy jednostkowe były do tego przeznaczone. Możesz użyć testów jednostkowych dla funkcji zwracających wartość stochastyczną, ale użyj stałego ziarna, w którym to przypadku w sposób, który nie jest stochastyczny, że tak powiem, dla Random seed, nie sądzę, testowanie jednostkowe jest to, co chcesz, na przykład dla RNGs to, co masz na myśli, to test systemu, w którym uruchamiasz RNG wiele razy i spojrzeć na dystrybucję lub momenty tego.

 0
Author: ddd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-11 14:16:00