Модульное тестирование метода, который может иметь случайное поведение - PullRequest
4 голосов
/ 18 сентября 2008

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

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

Я хочу проверить, что сгенерированные пароли соответствуют установленным нами правилам, но, конечно, результаты функции будут случайными (или, ну, в общем, псевдослучайными).

Что бы вы, ребята, сделали в модульном тесте? Сгенерировать кучу паролей, проверить, все ли они прошли, и считаете это достаточно хорошим?

Ответы [ 11 ]

8 голосов
/ 18 сентября 2008

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

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

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

4 голосов
/ 18 сентября 2008

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

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

2 голосов
/ 18 сентября 2008

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

Есть ли что-нибудь в кодовой базе, которая проверяет сгенерированные пароли, чтобы убедиться, что они достаточно случайны? Если нет, я могу взглянуть на создание логики для проверки сгенерированных паролей, их тестирование, а затем вы можете утверждать, что генератор случайных паролей работает (поскольку «плохие» не выйдут).

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

0 голосов
/ 14 февраля 2018

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

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

Представьте себе, что мы реализовали функцию, которая берет коллекцию красного и синего мрамора и выбирает один случайным образом, но весу можно присвоить вероятность, т. Е. Веса 2 и 1 означают, что красные мраморы в два раза чаще быть выбранным как синий мрамор.

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

Это не гарантирует, что наша функция ведет себя так, как задумано (если мы передаем равное количество красного и синего мраморов и имеем одинаковый вес, всегда ли мы получаем распределение 50/50 для большого количества испытаний?), Но в На практике это часто достаточно.

0 голосов
/ 01 октября 2008

Либо используйте фиксированное случайное начальное число, либо сделайте его воспроизводимым (т. Е. Производным от текущего дня)

0 голосов
/ 18 сентября 2008

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

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

0 голосов
/ 18 сентября 2008

Не зная, какие у вас правила, сложно сказать наверняка, но при условии, что они примерно такие, «пароль должен содержать не менее 8 символов, как минимум одну заглавную букву, одну строчную букву, одну цифру и один специальный символ». «тогда невозможно даже с помощью грубой силы проверить достаточное количество сгенерированных паролей, чтобы доказать правильность алгоритма (поскольку для этого потребуется где-то более 8 ^ 70 = 1,63x10 ^ 63 проверок в зависимости от того, сколько специальных символов вы назначите для использования, что займет очень и очень много времени, чтобы завершить).

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

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

0 голосов
/ 18 сентября 2008

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

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

0 голосов
/ 18 сентября 2008

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

0 голосов
/ 18 сентября 2008

Вы также можете посмотреть тестирование мутаций ( Шут для Java, Гекл для Ruby)

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