Несколько хороши ваши тесты? Протестируйте их с помощью мутатора Stryker
Вы взялись за новый проект и решили всё сделать правильно. Возможно даже разрабатывать через TDD. И вот, всё готово, все тесты зелёные, покрытие тестами полное, вы гордитесь своей работой. Затем от клиента приходит запрос на новый функционал. Вы что-то добавляете, также решаете что-то отрефакторить, т.к. лучше поняли домен и требования клиента, добавляете новые тесты, все тесты (и старые, и новые) проходят, всё прекрасно.
И тут приходит сообщение от клиента… В смысле «не работает»???
Внезапно вы находите ошибку, и не в новом функционале, а в исходной версии кода. Но как же так? Все тесты проходили. Оказывается, вы не охватили тестами все случаи, несмотря на 100% покрытие. Затем вы изменили кое-что здесь и там, и в результате функциональность уже не работает должным образом. Как снизить вероятность повторения такой ситуации?
Что такое мутационное тестирование?
Мутационное тестирование - это введение ошибок (мутантов) в ваш производственный код. Например, равенство заменяется неравенством, AND на OR и т.п. Затем выполняются тесты для каждого мутанта, и тесты должны провалиться! Неудача означает, что мутант убит. Если тесты проходят, мутант выжил, а значит, есть ложноположительные результаты.
Stryker делает всё это автоматически. Он поддерживает различные мутаторы, например арифметические операторы, равенство, логические операторы, мутации строк и даже LINQ. Вы можете посмотреть полный список доступных мутаторов в документации.
Stryker устанавливается как d
otnet tool глобально или для каждого проекта в отдельности. dotnet tool install dotnet-stryker
Затем он запускается из папки юнит-тестовdotnet stryker
и создаёт HTML отчёт с результатами мутационного тестирования (см. в верхней части рисунка ниже). Как видите, только 3 «мутанта» были убиты, а 23 выжили, и мы получаем результат мутационных тестов всего в 11,54%. Это значит, что нам нужно добавить юнит-тестов в систему и покрыть тестами случаи, когда мутанты выживают. Можно «провалиться» в каждую папку и каждый отдельный файл из отчёта, и посмотреть, какие мутационные тесты были выполнены, и их результат. Например, в нижней части рисунка мы видим «выжившего мутанта». То есть, у нас нет теста, проверяющего случай, когда _orderStatusId не равен OrderStatus.Submitted.Id, и нам нужно его добавить.Отдельный интересный пример – замена LINQ методов, например,
First/Single на FirstOrDefault/SingleOrDefault и наоборот. Здесь проверяется случайное неверное использование. В случае пустой коллекции First/Single должны выбрасывать исключение, тогда как *OrDefault версии нет.Итого
Вы можете спросить: когда следует запускать мутационные тесты? В CI/CD, локально или время от времени?
Пока не понятно. Я всё ещё новичок в мутационном тестировании. На данный момент думаю, имеет смысл добавить его как часть разработки. То есть, начиная работу с некоторым кодом, запустить Stryker, чтобы посмотреть хорошо ли код покрыт тестами. Если да, можно уверенно работать с этим кодом. Если нет - то сначала сосредоточьтесь на увеличении охвата, а затем на развитии кода. Сделать Stryker частью вашего CI/CD также возможно.
Stryker и мутационное тестирование в целом - не серебряная пуля. Я бы скорее назвал его страховкой. Закончили кодирование функции или исправление ошибки? Сделайте одолжение себе и своей команде и проверьте, охватывают ли ваши тесты все возможные случаи. Да? Отлично. Нет? Просто исправьте это.
Источник: https://lukaszcoding.com/how-good-are-your-net-tests-test-your-tests-with-stryker-mutator/