Комментарии 19
Никогда не устану поражаться, как люди упорно игнорируют единственно правильный способ тестирования подобного рода сценариев — property-based testing.
Технологии 25 лет скоро, а такое ощущение, будто против нее заговор. Вместо того, чтобы изобретать вручную все стопиццот пограничных условий (и обязательно парочку пропустить) — можно же определить набор свойств для вашего тестируемого объекта, и проверять именно их, отдав бездушной машине право нагенерировать входные данные (включая такие, о которых ни разработчик, ни тестировщик, — никогда не подумает).
В вашем случае — это два свойства: принадлежность кота и количество порций. Ну так и тестируйте ровно то, что хотите получить на выходе:
когда кот мой, исключение
AuthenticationException
не выбрасывается, и наоборот.когда кот мой и количество порций между
1
и4
, проверяйте сколько кот уже съел, иначе проверяйте, что выбрасывается соответствующее исключение.
Вот еще ссылка для шарпа: https://www.codit.eu/blog/property-based-testing-with-c/
А вот оригинальная разработка: https://en.wikipedia.org/wiki/QuickCheck
Джон Хьюз — умнейший человек и очень сильный разработчик, но в маркетинге он, явно, слабоват.
Интересно, как проверить, например, функцию, убирающую пробелы и меняющую цифры на точки во входной строке с помощью этого подхода?
функцию, убирающую пробелы и меняющую цифры на точки во входной строке
Если это не фигура речи, и вам действительно интересно, то вот:
▸ свойство №1: в результирующей строке не должно быть пробелов и/или цифр
▸ свойство №2: в результирующей строке должны присутствовать точки в местах, где на входе были цифры или точки, на всех остальных позициях ввод должен быть сохранен
В псевдокоде:
for all input <- inputs do
outcome = transformed(input)
refute outcome.find('[[::space::]]')
refute outcome.find('[[::digit::]]')
idx = 0
for i ∈ [0, length(input)) do
case input_char
'[[::space::]]' → assert true
'[[::digit::]]' → assert(outcome[++idx]) == '.'
other → assert(outcome[++idx]) == other
end
end
end
inputs
вам нагенерит тестовый фреймворк, причем таких, о которых вы и подумать не сумеете.
Можно ли контролировать inputs и насколько гибко?
Есть ли поддержка моков (например, чтоб замоканный вызов БД также все время возвращал разный ответ)?
Конечно можно, как угодно гибко.
Моки-то тут причем? Они вообще ортогональны, не вижу, какая связь, нужны моки — сделайте моки.
Неясно, зачем вы эти вопросы задаете мне, хотя я и ссылок дал, и ключевые слова все указал. Я не евангелист, я по доброте душевной подсказал, если интересно попробовать поработать с небессмысленными тестами — почитайте про матчасть, материалов — вагон.
Моки при том что если возвращать одно и то же значение из замоканной БД (а именно так чаще всего и делают), то толку в разнообразии входящих данных?
Из того что стало понятно про property-based тесты, вся их мощь в генерации входных данных. Если полагаться на значения по умолчанию, то не факт, что нагенерятся все граничные условия. А если генерить их руками, то парочку "граничных условий обязательно пропустите".
Вообщем поэтому этот метод судя по всему и не прижился, т.к. это по сути то же самое, что все и делают, создавая кучу искусственных кейсов, но в красивой оббертке.
Кейс не прижился потому, что подавляющее большинство — тупые дебилы.
Перечитайте, что такое «свойство».
С одной стороны соглашусь, что инициализация моков действительно не проблема. Её можно вынести в отдельную функцию, для которой, возвращаемые моками значения, станут теми же параметрами, которые сможет нагенерировать фреймворк.
Что меня больше беспокоит в этом подходе, так это сложность самих тестов. Она приближается к сложности тестируемой функции, а может и превосходит ее. Какая польза от настолько сложного теста, который в пору покрывать тестами? Кто будет "сторожить сторожей"?
Я бы ещё рекомендовал юзать DI
И если юзаются внешние либы, то не стоит забывать, что в них тоже могут быть баги)
Ну пример со сменой мин кол-ва порций и не должен быть красным. Проверка на условие меньше 2, а не меньше или равно.
Речь, видимо, о том, что код изменился до неузнаваемости, а тесты вообще ничего про это не сказали. Так быть не должно, иначе основная функция тестов (валидация корректности рефакторинга) сводится к нулю.
Да, всё верно)
А разве не в этом ли суть тестов, что после рефакторинга они все равно остаются зелеными, не зная ничего о том, какой именно был рефакторинг?
Возможно, при следующем рефакторинге из примера выше стоит поработать над магическими числами? А то так можно вечно обновлять циферки то в коде, то в тестах.
"добавить обращение к заглушке вместо реального сервиса "
Если сервис в какой-то момент изменит внутреннюю логику или вывод, то вы об этом из этого теста не узнаете. Поправьте если я не прав.
В таком случае лучше использовать подготовленные данные, сгенерированные ранее сервисом или вам нужен еще один тест, который будет подтверждать, что сервис работает согласно ожиданиям, чтобы тест был валидным.
Три смертных греха автотестов