Каков наилучший способ для модульного тестирования кода, который генерирует случайный вывод? - PullRequest
26 голосов
/ 18 июня 2010

В частности, у меня есть метод, который выбирает n элементов из списка таким образом, что% из них соответствует одному критерию, а b% соответствует второму, и так далее.В упрощенном примере можно выбрать 5 элементов, в которых 50% имеют заданное свойство со значением «истина», а 50% - «ложь»;В 50% случаев метод вернул бы 2 true / 3 false, а остальные 50%, 3 true / 2 false.

По статистике это означает, что за 100 прогонов я должен получить около 250 true /250 ложно, но из-за случайности 240/260 вполне возможно.

Каков наилучший способ провести юнит-тестирование?Я предполагаю, что, хотя технически 300/200 возможен, он, вероятно, не пройдет тест, если это произойдет.Существует ли общепринятый допуск для подобных случаев, и если да, то как вы определяете, что это такое?

Редактировать: В коде, над которым я работаю, я не могу позволить себе роскошь использоватьгенератор псевдослучайных чисел или механизм принудительного его выравнивания во времени, так как выбираемые списки генерируются на разных машинах.Мне нужно продемонстрировать, что со временем среднее количество элементов, соответствующих каждому критерию, будет стремиться к требуемому проценту.

Ответы [ 9 ]

22 голосов
/ 18 июня 2010

Случайные и статистические данные не приветствуются в модульных тестах. Модульные тесты должны всегда возвращать один и тот же результат . Всегда. Не в основном.

Что вы можете сделать, это попытаться удалить генератор случайной логики, которую вы тестируете. Затем вы можете смоделировать генератор случайных чисел и вернуть предопределенные значения.


Дополнительные мысли:

Вы можете изменить реализацию, чтобы сделать ее более тестируемой. Постарайтесь получить как можно меньше случайных значений. Например, вы можете получить только одно случайное значение, чтобы определить отклонение от среднего распределения. Это было бы легко проверить. Если случайное значение равно нулю, вы должны получить точное распределение, которое вы ожидаете в среднем. Если значение, например, 1,0, вы пропустите среднее значение по некоторому определенному коэффициенту, например, на 10%. Вы могли бы также реализовать некоторый гауссовский дистрибутив и т. Д. Я знаю, что здесь это не тема, но если вы свободны в реализации, как хотите, подумайте о тестируемости.

4 голосов
/ 18 июня 2010

Мне кажется, здесь есть по крайней мере три вещи, которые вы хотите проверить:

  1. Правильность процедуры, которая генерирует вывод с использованием случайного источника
  2. Чтораспределение случайного источника - это то, что вы ожидаете
  3. что распределение выхода - это то, что вы ожидаете

1 должно быть детерминированным, и вы можете протестировать его, предоставив выбранный наборизвестные «случайные» значения и входы и проверка того, что он выдает известные правильные выходы.Это было бы проще, если бы вы структурировали код так, чтобы случайный источник передавался в качестве аргумента, а не встраивался в код.

2 и 3 не могут быть проверены абсолютно.Вы можете выполнить тестирование до некоторого выбранного уровня достоверности, но вы должны быть готовы к тому, что такие тесты не пройдут в некоторых случаях.Вероятно, вы действительно хотите обратить внимание на то, что тест 3 проваливается гораздо чаще, чем тест 2, поскольку это может указывать на неправильность вашего алгоритма.

Применяемые тесты будут зависеть от ожидаемого распределения.Для 2 вы, скорее всего, ожидаете, что случайный источник будет равномерно распределен.Существуют различные тесты для этого, в зависимости от того, насколько вы хотите быть вовлечены, см., Например, Тесты для генераторов псевдослучайных чисел на этой странице .

Ожидаемое распределение для 3 будет зависеть оченьмногое на том, что вы производите.Простой случай 50-50 в вопросе в точности эквивалентен тестированию на честную монету , но, очевидно, другие случаи будут более сложными.Если вы можете определить, каким должно быть распределение, может помочь критерий хи-квадрат против него.

4 голосов
/ 18 июня 2010

Многие вероятностные алгоритмы, например, в научных вычислениях, используют генераторы псевдо случайных чисел вместо true генератора случайных чисел.Даже если они не являются случайными, тщательно выбранный генератор псевдо случайных чисел отлично справится с этой задачей.

Одно преимущество случайного числа псевдо Генератор в том, что последовательность случайных чисел, которую они производят, является полностью воспроизводимой .Поскольку алгоритм является детерминированным, один и тот же seed всегда будет генерировать одну и ту же последовательность.Это часто является решающим фактором, почему они выбираются в первую очередь, потому что эксперименты должны быть повторяемыми, воспроизводимые результаты.

Эта концепция также применима для тестирования.Компоненты могут быть спроектированы таким образом, что вы можете подключить любой источник случайных чисел.Для тестирования вы можете использовать генераторы, которые последовательно засеваются.Затем результат будет повторяем, что подходит для тестирования.

Обратите внимание, что если на самом деле требуется true случайное число, вы можете все еще проверить его таким образомДо тех пор, пока компонент имеет подключаемый источник случайных чисел.Вы можете повторно подключить одну и ту же последовательность (которая может быть действительно случайной в случае необходимости) к тому же компоненту для тестирования.

4 голосов
/ 18 июня 2010

Согласно имеющейся у вас статистической информации, определите диапазон вместо определенного отдельного значения в результате.

3 голосов
/ 18 июня 2010

Это зависит от того, как вы используете свой набор тестов.Если вы запускаете его каждые несколько секунд из-за разработки, основанной на тестировании, и агрессивного рефакторинга, то очень важно, чтобы он не проваливался внезапно, потому что это приводит к серьезным сбоям и снижению производительности, поэтому вы должны выбрать порог, который практически невозможендостичь хорошо себя зарекомендовавшей себя реализации.Если вы запускаете свои тесты один раз в ночь и у вас есть время для расследования сбоев, вы можете быть намного строже.

Ни при каких обстоятельствах не следует развертывать что-либо, что приведет к частым неисследованным сбоям - это сводит на нет всю цель наличиянабор тестов, и значительно снижает его ценность для команды.

2 голосов
/ 18 июня 2010

Вы должны проверить распределение результатов в «единичном» модульном тесте, т. Е. Чтобы результат был как можно ближе к желаемому распределению, насколько это возможно при любом отдельном прогоне.Для вашего примера 2 true / 3 false в порядке, 4 true / 1 false в результате не в порядке.

Также вы можете написать тесты, которые выполняют метод, например, 100 раз и проверяют, что среднее из распределений"достаточно близко" к желаемой скорости.Это пограничный случай - запуск больших партий может занять значительное время, поэтому вы можете запускать эти тесты отдельно от своих «обычных» модульных тестов.Кроме того, как указывает Стефан Штайнеггер, такой тест время от времени будет проваливаться, если вы определите «достаточно близко», или начнете быть бессмысленным, если вы определите порог слишком свободно.Так что это сложный случай ...

1 голос
/ 18 июня 2010

Я думаю, что если бы у меня была такая же проблема, я, вероятно, построил бы доверительный интервал для обнаружения аномалий, если у вас есть статистика о среднем / stddev и тому подобное. Так что в вашем случае, если среднее ожидаемое значение равно 250, создайте 95% доверительный интервал вокруг среднего значения, используя нормальное распределение. Если результаты выходят за этот интервал, вы проваливаете тест.

см. больше

0 голосов
/ 18 июня 2010

Сначала вы должны знать, какое распределение должно быть результатом процесса генерации случайных чисел.В вашем случае вы генерируете результат, который равен 0 или 1 с вероятностью -0,5.Это описывает биномиальное распределение с p = 0,5.

Учитывая размер выборки n, вы можете построить (как предполагал более ранний автор) доверительный интервал вокруг среднего значения.Вы также можете делать различные заявления о вероятности получения, например, 240 или менее любого результата при n = 500.

Вы можете использовать допущение нормального распределения для значений N больше 20, если p не очень велико или очень мало.В Википедии есть больше об этом.

0 голосов
/ 18 июня 2010

Почему бы не перефакторизовать код генерации случайных чисел и позволить ему использовать и модуль модульного тестирования, и исходный код? Вы пытаетесь проверить свой алгоритм, а не случайную последовательность, верно?

...