Использование случайности и / или итераций в модульных тестах? - PullRequest
7 голосов
/ 23 апреля 2009

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

Но разве это очень плохо?

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

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

ОБНОВЛЕНИЕ:

Я сам не использую эту технику, мне просто интересно. Я знаю, что случайность может быть хорошим инструментом, если вы можете сделать его воспроизводимым, когда вам нужно.
Самым интересным ответом был «пушистый» совет от Ливена:

http://en.wikipedia.org/wiki/Fuzz_testing

ТХ

Ответы [ 11 ]

5 голосов
/ 23 апреля 2009
  1. Случайный ввод - тесты не будут повторяемыми (выдают последовательные результаты при каждом запуске и, следовательно, не считаются хорошими юнит-тестами. Тесты не должны передумать.
  2. Range tests / RowTests - хороши, если они не замедляют выполнение набора тестов. Каждый тест должен выполняться как fast , насколько это возможно. (Тестовый набор «сделано за 30 секунд» запускается чаще, чем 10-минутный) - предпочтительно 100 мс или меньше. Тем не менее, каждый вход (тестовые данные) должен быть «представительным» входом. Если все входные значения одинаковы, тестирование каждого из них не добавляет никакого значения, а является просто обработкой числа. Вам просто нужен один представитель из этого набора значений. Вам также нужны представители для граничных условий и «специальных» значений.

Подробнее о руководящих принципах или поясняющих элементах - см. «Что дает хороший модульный тест?»

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

Ответ на разъяснение ФП:

  • Если вы используете одно и то же начальное значение (вход теста) для случайного генератора без каждого теста, ваш тест не является случайным - значения могут быть определены заранее. Однако для модульного теста в идеале не требуется ввод / вывод, поэтому в тестовых случаях xUnit есть подпись void TC ().
  • Если вы используете разные начальные значения при каждом запуске, теперь ваши тесты являются случайными и не повторяются. Конечно, вы можете найти специальное начальное значение в ваших файлах журналов, чтобы узнать, что не удалось (и воспроизвести ошибку), но мне нравятся мои тесты, чтобы мгновенно сообщить мне, что не удалось - например, красный TestConversionForEnums () сообщает мне, что код преобразования Enum не проверяется.

Repeatable - подразумевает, что каждый раз, когда тест запускается на SUT, он выдает один и тот же результат (проход / сбой) ... не «Могу ли я снова воспроизвести сбой теста?» ( Повторяется! = Воспроизводимо ). Повторимся ... этот вид исследовательского тестирования может быть полезен для определения большего количества тестовых случаев, но я бы не стал добавлять это в мой набор тестов, который я запускаю каждый раз, когда делаю изменение кода в течение дня. Я бы порекомендовал провести предварительное тестирование вручную, найти несколько хороших (некоторые могут использовать садистские) тестеров, которые будут разбираться с вашим кодом ... найдут вам больше тестовых случаев, чем генератор случайных входных данных.

5 голосов
/ 23 апреля 2009

Модульные тесты должны быть быстрыми. если они не люди, они не будут регулярно ими управлять. Иногда я делал код для проверки всего диапазона, но @ Ignore'd закомментировал его в конце, потому что это делало тесты слишком медленными. Если бы я использовал случайные значения, я бы выбрал PRNG с фиксированными начальными значениями, чтобы каждый прогон на самом деле проверял одни и те же числа.

3 голосов
/ 24 апреля 2009

Я использовал случайность в моих тестовых случаях. Он обнаружил некоторые ошибки в SUT и несколько ошибок в моем тестовом примере.

Обратите внимание, что тестовый пример усложняется при использовании randomnes.

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

В общем, я возвращаюсь к использованию случайности, но не отмахиваюсь от нее. Как и в любой технике, у нее есть свои ценности.

Для лучшего объяснения того, что вы ищете, найдите термин fuzzing

3 голосов
/ 23 апреля 2009

То, что вы описываете, обычно называется тестированием на основе спецификаций и реализуется такими структурами, как QuickCheck (Haskell), scalacheck (Scala) и Quviq QuickCheck (Эрланг).

Инструменты тестирования на основе данных (такие как DataProvider в TestNG ) могут достичь аналогичных результатов.

Основополагающий принцип заключается в том, чтобы генерировать входные данные для испытуемого субъекта на основе некоторой спецификации, и это далеко не «плохая практика».

2 голосов
/ 23 апреля 2009

Что вы тестируете? Генератор случайных чисел? Или твой код?

Если ваш код, что если в коде есть ошибка, которая выдает случайные числа?

Что если вам нужно воспроизвести проблему, продолжаете ли вы перезапускать тест, надеясь, что в конечном итоге он будет использовать ту же последовательность, что и вы, когда вы обнаружили проблему?

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

Другими словами, ваши "случайные числа" - это просто "последовательность чисел, которые меня не особо волнуют".

1 голос
/ 23 апреля 2009

Я использовал случайность для отладки полевой проблемы с конечным автоматом, пропускающим ресурс. Мы проверили код, выполнили юнит-тесты и не смогли воспроизвести утечку.

Мы подали случайные события из всего возможного пространства событий в среду тестирования конечного автомата. Мы смотрели на инварианты после каждого события и останавливались, когда они были нарушены.

Случайные события в конечном итоге выявили последовательность событий, которые привели к утечке. Конечный автомат пропустил ресурс, когда во время восстановления после первой ошибки произошла вторая ошибка.

Затем мы смогли воспроизвести утечку в поле.

Так что случайность нашла проблему, которую трудно было найти иначе. Немного грубой силы, но компьютер не против работать в выходные дни.

1 голос
/ 23 апреля 2009

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

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

1 голос
/ 23 апреля 2009

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

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

0 голосов
/ 02 мая 2009

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

В модульном тесте могут использоваться случайные значения в ожидаемом диапазоне, если возможно всегда сохранять входы / выходы (если есть) до и после.

0 голосов
/ 25 апреля 2009

См. Работу Дэвида Саффа Теоретическое тестирование .

Обычно я бы избегал случайности в юнит-тестах, но теоретические вещи интригуют.

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