Тестирование на Основе Свойств. Воспроизведение
Теория
Простой пример
Реальный пример
Собственный генератор
Для каждого тестируемого свойства FsCheck генерирует случайные входные значения. Эти значения могут быть разными для каждого запуска теста, что означает, что каждый запуск может закончиться разными результатами. Поэтому, если у вас было неправильное входное значение, которое не прошло тест в предыдущий раз, вполне возможно, что при следующем запуске теста вы больше не увидите этот неправильный вход. Для простых входных значений это не должно быть проблемой. Но если вы используете более сложные входные данные, повторить неудачный тест может быть трудно.
Если посмотреть на выходные данные неудавшегося теста, можно заметить строку вроде
Falsifiable, after 3 tests (4241 shrinks) (StdGen(318823861,297138967)).StdGen – это начальные значения, которые FsCheck использовал для генерации входных данных. Если вы хотите использовать в своём тесте точно такие же входные данные, используйте это значение в свойстве Replay атрибута Property:
[Property(Replay="318823861,297138967")]Приёмочные тесты на основе свойств
public bool ValidationShouldFail(long num)
{
…
}
Ещё одна область, где могут пригодиться тесты на основе свойств, — это случаи, когда вам нужен своего рода приёмочный тест для какого-то кода. Например, у вас есть некоторый метод, в правильности которого вы уверены, но необходимо провести его рефакторинг, либо он недостаточно быстр. Вы можете написать тест на основе свойств, в котором свойство, которое должно соблюдаться, заключается в том, что для любых входных данных результат изначального метода должен совпадать с результатом нового. Затем увеличьте количество случайных входных данных настолько, чтобы можно было быть уверенным в правильности. И если тесты проходят, значит новый метод работает правильно.
Итого
Тесты на основе свойств полезны, но не являются панацеей. Их может быть сложнее читать другим разработчикам, которые не привыкли проводить тестирование на основе свойств. Когда вы решаете реализовать свои собственные произвольные алгоритмы и ограничиваете возможные произвольные значения, вы рискуете упустить важные случаи из-за излишней строгости, как и при написании обычных тестов. Тесты на основе свойств также выполняются медленнее: по умолчанию они генерируют 100 случайных входных данных и проверяют их. Поскольку вы имеете дело со случайностью, это также означает, что два прогона теста не идентичны. У вас может быть удачный, а затем неудачный прогон. Если второй запуск выявит реальную проблему, то всё в порядке. Следует написать специальный модульный тест для этого случая, а затем исправить проблему. Однако если это связано с тем, что один из ваших генераторов случайно генерирует значения, которые сильно отличаются от ожидаемых входных данных, выявить и устранить проблему может быть сложнее. Это связано с тем, что сначала вам нужно идентифицировать генератор, дающий неожиданные значения, и обернуть его механизмом фильтрации. И, хотя это возможно сделать, это всё же больше работы, чем простое изменение постоянного значения, определённого в модульном тесте.
Тестирование на основе свойств – очень мощный инструмент, о котором часто забывают. Оно действительно может выявить скрытые и неочевидные ошибки в самых сложных участках кода.
Источники:
- https://bartwullems.blogspot.com/2023/01/property-based-testing-in-cpart-5.html
- https://rasmus-feldthaus.medium.com/supercharge-your-testing-with-property-based-tests-bc3a7b75ca9f