Ответы на ваши вопросы
Есть ли такая вещь, как иметь слишком много юнит-тестов?
Конечно ... Вы можете, например, иметь несколько тестов, которые на первый взгляд кажутся разными, но на самом деле тестируют одно и то же (логически зависят от одних и тех же строк "интересного" тестируемого кода приложения).
Или вы можете протестировать внутренние компоненты вашего кода, которые никогда не выходят наружу (то есть не являются частью какого-либо контракта интерфейса), где можно спорить о том, имеет ли это смысл вообще. Например, точная формулировка сообщений внутреннего журнала или что-то еще.
Мне было поручено написание модульных тестов для существующего приложения. После завершения моего первого файла у меня есть 717 строк тестового кода для 419 строк исходного кода.
Это кажется мне вполне нормальным. Ваши тесты тратят много строк кода на настройку и разборку поверх реальных тестов. Соотношение может улучшиться, а может и нет. Я сам испытываю большие трудности с тестированием и часто трачу больше времени и ресурсов на тесты, чем на реальный код.
Будет ли это соотношение неуправляемым по мере увеличения покрытия кода?
Соотношение не имеет большого значения. Есть и другие качества тестов, которые делают их неуправляемыми. Если вам регулярно приходится проводить рефакторинг целого ряда тестов, когда вы делаете довольно простые изменения в вашем коде, вы должны внимательно посмотреть на причины. И дело не в том, сколько строк у вас есть, а в том, как вы подходите к кодированию тестов.
Мое понимание модульного тестирования состояло в том, чтобы протестировать каждый метод в классе, чтобы убедиться, что каждый метод работал, как ожидалось.
Это верно для «модульных» тестов в строгом смысле. Здесь «единица» - это что-то вроде метода или класса. Цель «модульного» тестирования состоит в том, чтобы тестировать только одну конкретную единицу кода, а не всю систему. В идеале вы должны удалить всю оставшуюся часть системы (используя удвоения или еще много чего).
Однако в запросе на получение поддержки мой технический руководитель отметил, что мне следует сосредоточиться на тестировании более высокого уровня.
Затем вы попали в ловушку, предполагая, что люди на самом деле имели в виду юнит-тесты, когда они говорили юнит-тесты. Я встречал много программистов, которые говорят «модульный тест», но имеют в виду нечто совсем другое.
Он предложил протестировать 4-5 вариантов использования, которые чаще всего используются в рассматриваемом классе, а не исчерпывающе тестировать каждую функцию.
Конечно, только концентрация на верхних 80% важного кода также снижает нагрузку ... Я ценю, что вы высоко цените своего босса, но это не делает меня оптимальным выбором.
Для меня 100% покрытие модульных тестов - высокая цель, но даже если бы мы достигли только 50%, мы бы знали, что 100% из этих 50% были покрыты.
Я не знаю, что такое «покрытие модульных тестов». Я предполагаю, что вы имеете в виду «покрытие кода», то есть после запуска набора тестов каждая строка кода (= 100%) была выполнена как минимум один раз.
Это хороший приблизительный показатель, но далеко не лучший стандарт, за который можно было бы стрелять. Простое выполнение строк кода - это не вся картина; например, это не учитывает разные пути через сложные, вложенные ветви. Это скорее показатель, который указывает пальцем на фрагменты кода, которые тестируются слишком мало (очевидно, если класс покрывает 10% или 5% покрытия кода, то что-то не так); с другой стороны, 100% покрытие не скажет вам, достаточно ли вы прошли тестирование или тестировали ли вы правильно.
Интеграционное тестирование
Меня по-настоящему раздражает, когда люди постоянно говорят о модульном тестировании сегодня, по умолчанию. На мой взгляд (и опыт), модульное тестирование отлично подходит для библиотек / API; в более ориентированных на бизнес областях (где мы говорим о вариантах использования, как в рассматриваемом вопросе), они не обязательно являются лучшим вариантом.
Для общего кода приложения и в среднем бизнесе (где важно зарабатывать деньги, не укладываться в сроки и удовлетворять потребности клиентов, и вы в основном хотите избежать ошибок, которые прямо скажутся на лице пользователя или могут привести к реальным бедствиям), мы не Говоря о запуске ракет НАСА), интеграционные или функциональные тесты гораздо полезнее.
Они идут рука об руку с разработкой, управляемой поведением, или разработкой, ориентированной на особенности; те, по определению, не работают с (строгими) модульными тестами.
Короче говоря, тест интеграции / функциональности выполняет весь стек приложений. В веб-приложении оно будет действовать как браузер, просматривающий приложение (и нет, очевидно, это не должно быть настолько упрощенным, для этого существуют очень мощные фреймворки - посмотрите http: // cucumber. ИО для примера).
О, чтобы ответить на ваши последние вопросы: вы обеспечите высокий уровень охвата всей командой, убедившись, что новая функция запрограммирована только после того, как ее тестирование будет выполнено и не выполнено. И да, это означает, что каждая функция. Это гарантирует вам 100% (положительную) характеристику покрытия. Это по определению гарантирует, что функция вашего приложения никогда не исчезнет. Это не гарантирует 100% покрытия кода (например, если вы не будете активно программировать негативные функции, вы не будете осуществлять обработку ошибок / обработку исключений).
Это не гарантирует вам приложение без ошибок; конечно, вы захотите написать функциональные тесты для очевидных или очень опасных ситуаций с ошибками, неправильного ввода данных пользователем, взлома (например, управления сессиями, безопасности и т. д.) и т. д .; но даже только программирование положительных тестов имеет огромное преимущество и вполне осуществимо с современными, мощными средами.
Тесты функций / интеграции, очевидно, имеют свои собственные черви (например, производительность; избыточное тестирование сторонних фреймворков; поскольку вы, как правило, не используете двойные числа, по моему опыту, как правило, их сложнее написать), но я ' d) ежедневно принимать приложение, проверенное на положительную функциональность, а не приложение, проверенное на 100% покрытие кода (а не библиотеку!).