Есть ли такая вещь, как иметь слишком много юнит-тестов?

139

Мне было поручено написание модульных тестов для существующего приложения. После завершения моего первого файла у меня есть 717 строк тестового кода для 419 строк исходного кода.

Будет ли это соотношение неуправляемым по мере увеличения покрытия кода?

Мое понимание модульного тестирования состояло в том, чтобы протестировать каждый метод в классе, чтобы убедиться, что каждый метод работал, как ожидалось. Однако в запросе на получение поддержки мой технический руководитель отметил, что мне следует сосредоточиться на тестировании более высокого уровня. Он предложил протестировать 4-5 вариантов использования, которые чаще всего используются в рассматриваемом классе, а не исчерпывающе тестировать каждую функцию.

Я доверяю комментарию моего технического лидера. У него больше опыта, чем у меня, и у него есть лучшие инстинкты, когда дело доходит до разработки программного обеспечения. Но как команда из нескольких человек пишет тесты для такого неоднозначного стандарта; то есть откуда я знаю своих сверстников и разделяю ту же идею для «наиболее распространенных вариантов использования»?

Для меня 100% покрытие модульных тестов - высокая цель, но даже если бы мы достигли только 50%, мы бы знали, что 100% из этих 50% были покрыты. В противном случае написание тестов для части каждого файла оставляет много места для обмана.

user2954463
источник
145
По-разному. Вы пишете игру в крестики-нолики или пишете код для управления ядерным реактором?
Брайан Оукли
11
При достаточном количестве модульных тестов вы можете обнаружить экзотические проблемы с реализацией оборудования, такие как ошибка Pentium FDIV или корреляции в криптографических примитивах, поэтому кажется, что нет жесткого предела, который не может быть полезен для дальнейших модульных тестов. Просто практический предел того, когда это слишком дорого.
Nat
5
Тестирование на более высоких уровнях предоставит вам лучшее представление о реальном освещении. Под реальным освещением я подразумеваю, что такое случается чаще при регулярном использовании системы. Такого рода покрытие вы хотите достичь в первую очередь. Из тех 50%, которые достигли последнего, могут иметь YAGNI или мертвый код, который после удаления также будет способствовать увеличению общего покрытия.
Laiv
5
Если вы получаете слишком много тестов (которых у вас сейчас нет), наиболее вероятная проблема заключается в том, что код, который вы тестируете, делает слишком много. Так что единой ответственности не соблюдается. Когда код хорошо разделен, тестирование также не будет создавать больших нагрузок. Если уроки делают много, имеют много побочных эффектов и т. Д., Это станет кошмаром.
Люк Франкен
12
Документ по тестированию sqlite очень интересен : sqlite.org/testing.html . Цитата: «Библиотека SQLite состоит примерно из 122,9 KSLOC кода C. Для сравнения, в проекте в 745 раз больше тестового кода и тестовых скриптов - 91596,1 KSLOC».
user60561

Ответы:

180

Да, со 100% покрытием вы напишите некоторые тесты, которые вам не нужны. К сожалению, единственный надежный способ определить, какие тесты вам не нужны, - написать все, а затем подождать 10 лет или около того, чтобы узнать, какие из них никогда не заканчивались.

Поддержание большого количества тестов обычно не проблематично. Многие команды имеют автоматизированную интеграцию и системные тесты в дополнение к 100% охвату модульных тестов.

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

Карл Билефельдт
источник
11
Спасибо за Ваш ответ. Это помогло поставить мой вопрос в перспективе и решить реальную проблему - мое отношение! +1
user2954463
43
@astra Твоё отношение не так уж и плохо. Хорошо задаться вопросом почему. Чтобы ответить на ваш другой вопрос, отличный вопрос: «Откуда я знаю, что мои сверстники и я разделяю ту же идею для« наиболее распространенных вариантов использования »? Вы заставляете их взглянуть на ваши тесты. Посмотрите на их. Поговорите о них. много, и, возможно, они тоже. Тесты проверки кода редко являются пустой тратой времени. Хотя я
стараюсь
18
Тест, который никогда не пройдет 10 лет, даже не гарантирует, что он не нужен, он может закончиться неудачей в 11 году.
Pharap
24
Прагматично, вы могли бы принять противоположный подход. Напишите тесты, которые, по вашему мнению, охватывают общие случаи. Но затем, каждый раз, когда вы сталкиваетесь с ошибкой, пишите тест, чтобы охватить эту область.
Станний
10
@Pharap Моя единственная проблема, связанная с этим ответом, заключается в том, что существует неявное предположение, что тест может повысить ценность только в случае неудачи. Хороший юнит-тест также предоставляет отличную форму живой документации. Это также добавило ценности при написании теста, заставив задуматься о возможности повторного использования / компоновки / инкапсуляции. Непроверенный код в моем опыте - это негибкие монолитные звери.
АрЦ
66

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

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

Фрэнк Хилман
источник
16
Голосование за указание предварительных условий, постусловий и инвариантов должно рассматриваться как юнит-тестирование. Таким образом, каждое использование является модульным тестом, когда этот код отладки активен.
Persixty
Это отличный ответ и идеально соответствует моему опыту.
Тони Эннис
И еще одна проблема: если у вас есть закрытые проверки (вы действительно должны!) С большим количеством низкого качества, возможно, даже длительные тесты замедлят все без каких-либо реальных преимуществ. И тогда, очевидно, забавный факт, когда вы меняете одну вещь в классе, и сотни тестов проваливаются.
Voo
3
Это гораздо лучший ответ, чем принятый! «В некоторых случаях большая часть усилий по разработке состоит в обновлении некачественных тестов», - я испытал это, и это отстой. В некоторых отношениях это больше, чем отсутствие тестов.
Бенджамин Ходжсон
36

Ответы на ваши вопросы

Есть ли такая вещь, как иметь слишком много юнит-тестов?

Конечно ... Вы можете, например, иметь несколько тестов, которые на первый взгляд кажутся разными, но на самом деле тестируют одно и то же (логически зависят от одних и тех же строк "интересного" тестируемого кода приложения).

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

Мне было поручено написание модульных тестов для существующего приложения. После завершения моего первого файла у меня есть 717 строк тестового кода для 419 строк исходного кода.

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

Будет ли это соотношение неуправляемым по мере увеличения покрытия кода?

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

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

Это верно для «модульных» тестов в строгом смысле. Здесь «единица» - это что-то вроде метода или класса. Цель «модульного» тестирования состоит в том, чтобы тестировать только одну конкретную единицу кода, а не всю систему. В идеале вы должны удалить всю оставшуюся часть системы (используя удвоения или еще много чего).

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

Затем вы попали в ловушку, предполагая, что люди на самом деле имели в виду юнит-тесты, когда они говорили юнит-тесты. Я встречал много программистов, которые говорят «модульный тест», но имеют в виду нечто совсем другое.

Он предложил протестировать 4-5 вариантов использования, которые чаще всего используются в рассматриваемом классе, а не исчерпывающе тестировать каждую функцию.

Конечно, только концентрация на верхних 80% важного кода также снижает нагрузку ... Я ценю, что вы высоко цените своего босса, но это не делает меня оптимальным выбором.

Для меня 100% покрытие модульных тестов - высокая цель, но даже если бы мы достигли только 50%, мы бы знали, что 100% из этих 50% были покрыты.

Я не знаю, что такое «покрытие модульных тестов». Я предполагаю, что вы имеете в виду «покрытие кода», то есть после запуска набора тестов каждая строка кода (= 100%) была выполнена как минимум один раз.

Это хороший приблизительный показатель, но далеко не лучший стандарт, за который можно было бы стрелять. Простое выполнение строк кода - это не вся картина; например, это не учитывает разные пути через сложные, вложенные ветви. Это скорее показатель, который указывает пальцем на фрагменты кода, которые тестируются слишком мало (очевидно, если класс покрывает 10% или 5% покрытия кода, то что-то не так); с другой стороны, 100% покрытие не скажет вам, достаточно ли вы прошли тестирование или тестировали ли вы правильно.

Интеграционное тестирование

Меня по-настоящему раздражает, когда люди постоянно говорят о модульном тестировании сегодня, по умолчанию. На мой взгляд (и опыт), модульное тестирование отлично подходит для библиотек / API; в более ориентированных на бизнес областях (где мы говорим о вариантах использования, как в рассматриваемом вопросе), они не обязательно являются лучшим вариантом.

Для общего кода приложения и в среднем бизнесе (где важно зарабатывать деньги, не укладываться в сроки и удовлетворять потребности клиентов, и вы в основном хотите избежать ошибок, которые прямо скажутся на лице пользователя или могут привести к реальным бедствиям), мы не Говоря о запуске ракет НАСА), интеграционные или функциональные тесты гораздо полезнее.

Они идут рука об руку с разработкой, управляемой поведением, или разработкой, ориентированной на особенности; те, по определению, не работают с (строгими) модульными тестами.

Короче говоря, тест интеграции / функциональности выполняет весь стек приложений. В веб-приложении оно будет действовать как браузер, просматривающий приложение (и нет, очевидно, это не должно быть настолько упрощенным, для этого существуют очень мощные фреймворки - посмотрите http: // cucumber. ИО для примера).

О, чтобы ответить на ваши последние вопросы: вы обеспечите высокий уровень охвата всей командой, убедившись, что новая функция запрограммирована только после того, как ее тестирование будет выполнено и не выполнено. И да, это означает, что каждая функция. Это гарантирует вам 100% (положительную) характеристику покрытия. Это по определению гарантирует, что функция вашего приложения никогда не исчезнет. Это не гарантирует 100% покрытия кода (например, если вы не будете активно программировать негативные функции, вы не будете осуществлять обработку ошибок / обработку исключений).

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

Тесты функций / интеграции, очевидно, имеют свои собственные черви (например, производительность; избыточное тестирование сторонних фреймворков; поскольку вы, как правило, не используете двойные числа, по моему опыту, как правило, их сложнее написать), но я ' d) ежедневно принимать приложение, проверенное на положительную функциональность, а не приложение, проверенное на 100% покрытие кода (а не библиотеку!).

Anoe
источник
1
Интеграционные тесты хороши, но не являются заменой для модульных тестов, а также для бизнес-приложений. С ними связано множество проблем: а) они по определению занимают много времени (это также означает, что инкрементальные тесты практически бесполезны), б) они невероятно трудно точно определить реальную проблему (о 50 тестов интеграции просто провалились, какое изменение вызвало это?) и в) они покрывают одни и те же пути кода неоднократно.
Voo
1
а) является проблемой, потому что это делает выполнение тестов на стробированных регистрациях громоздким и снижает вероятность того, что программисты будут запускать тесты повторно во время разработки, что в сочетании с б) снижает эффективность и способность быстро диагностировать ошибки. c) означает, что изменение одной мелочи может легко привести к сбою десятков или сотен (уже там) ваших интеграционных тестов, что означает, что вы потратите немало времени на их исправление. Это также означает, что интеграционные тесты в основном тестируют только удачные пути, потому что написание этих тестов нацелено громоздко или невозможно.
Voo
1
@ Voo, все, что вы написали, правда, и, насколько я могу судить, я уже упомянул все проблемы, которые вы отметили в ответе ...
AnoE
Если вы согласны с этим резюме, я действительно не понимаю, как вы можете прийти к выводу, что вы бы предпочли интеграционные тесты юнит-тестам. Комплексные тесты интеграции интеграции больших программ занимают часы или даже дни, они замечательны, но практически бесполезны при реальной разработке. И ваши приемочные тесты (которые все делают, верно?) Обнаружат многие из тех же проблем, которые обнаружат интеграционные тесты, которые будут пропущены модульными тестами - наоборот, это не так.
Voo
24

Да, возможно иметь слишком много юнит-тестов. Если у вас 100% охват модульными тестами и, например, нет интеграционных тестов, у вас есть явная проблема.

Некоторые сценарии:

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

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

  2. Вы можете иметь разумное покрытие для каждого коммита с 20% тестов, которые у вас есть, оставляя 80% для интеграции или, по крайней мере, для отдельных тестовых прохождений; Основными негативными эффектами, которые вы видите в этом сценарии, являются медленные изменения, так как вам приходится долго ждать выполнения тестов.

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

Я особенно согласен с предложением получить 50% -ное покрытие на 100% файлов вместо 100% -ного покрытия на 50% файлов; сосредоточьте свои первоначальные усилия на наиболее распространенных положительных случаях и наиболее опасных отрицательных случаях, не вкладывайте слишком много в обработку ошибок и необычные пути не потому, что они не важны, а потому, что у вас ограниченное время и бесконечная вселенная тестирования, так что вам нужно расставить приоритеты в любом случае.

Бруно Гардиа
источник
2
Это не проблема для модульных тестов, но для организации, которая неправильно определила свои приоритеты, требуя определенного числа для покрытия модульных тестов, не затрачивая ресурсы на создание и выполнение надлежащих тестов на других уровнях.
jwenting
2
Согласитесь с №3, а также распространите его на ручную передачу экземпляров классов более низкого уровня классам более высокого уровня. Если высокоуровневая вещь полагается на какую-то низкоуровневую вещь, чтобы что-то сделать, это нормально. Если бы это скрывало детали этого от абонентов, я бы назвал это хорошим дизайном. Но если вы затем сделаете низкоуровневую вещь частью интерфейса высокоуровневой вещи и сделаете так, чтобы вызывающие абоненты передавали ее, потому что это делает ваши тесты красивыми, теперь хвост виляет собакой. (Если вещи низкого уровня повторно используются во многих местах и ​​сильно меняются, это меняет вещи. По моему опыту, это не было типичным.)
johncip
Мне нравится ваше описание @johncip, определенно это частый пример того, как хороший класс становится ужасным, добавляя кучу ненужных обязательных параметров в конструктор ...
Bruno Guardia
19

Имейте в виду, что каждый тест имеет свою цену и выгоду. Недостатки включают в себя:

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

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

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

Секрет Соломонова
источник
12

Да, есть такая вещь, как слишком много юнит-тестов.

Пока тестирование хорошо, каждый юнит-тест:

  • Потенциальная нагрузка на обслуживание, тесно связанная с API

  • Время, которое можно потратить на что-то другое

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

Целесообразно стремиться к 100-процентному охвату кода, но это далеко не означает набор тестов, каждый из которых независимо обеспечивает 100-процентное покрытие кода в определенной точке входа (функция / метод / вызов и т. Д.).

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

Прагматика для большинства кода указывает:

  1. Убедитесь, что у вас есть 100% покрытие точек входа (все как-то проверяется) и стремитесь быть близкими к 100% покрытию кода «без ошибок».

  2. Проверьте любые соответствующие минимальные / максимальные значения или размеры

  3. Протестируйте все, что вы считаете забавным особым случаем, особенно «странные» значения

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

Для более сложных алгоритмов рассмотрим также:

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

Например, проверьте алгоритм сортировки с некоторым рандомизированным вводом, и проверка данных сортируется в конце путем сканирования.

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

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

Ключевым уроком является добавление тестов при обнаружении ошибок. Что приводит меня к моему лучшему уроку по разработке юнит-тестов:

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

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

Это дает наилучший результат (один тест в целом - тестирование нескольких компонентов) и оставляет больше возможностей для перепроектирования и уточнения, поскольку в тестах используется только «внешний» интерфейс, который имеет тенденцию быть более стабильным.

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

Persixty
источник
4
Я бы не сказал, что 100% охват прагматичен. 100% охват - это чрезвычайно высокий стандарт.
Брайан Оукли
К сожалению, даже рандомизированный метод может пропустить ошибки. Там нет замены для доказательств, даже если неформальные.
Фрэнк Хилман
@BryanOakley Точка занята. Это преувеличение. Но более важно быть ближе к этому, чем люди отдают должное. «Я проверил легкий путь, это все хорошо» всегда будет вызывать проблемы позже.
Persixty
@FrankHileman Вопрос не был «Является ли модульное тестирование хорошей заменой для тщательного проектирования программного обеспечения, статической проверки логики и алгоритмов проверки», тогда ответ «нет». Ни один из методов не будет производить качественное программное обеспечение самостоятельно.
Persixty
3

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

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

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

Следующие наиболее ценные тесты - это те, которые имеют экстремальные пределы или граничные точки. Например, функция, которая принимает (основанные на 1) месяцы года, должна быть проверена с 0, 1, 12 и 13, чтобы вы знали, что допустимые недействительные переходы находятся в нужном месте. Это слишком тестирование, чтобы использовать 2..11 для этих тестов.

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

Тоби Спейт
источник
3

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

Это понимание неверно.

Юнит тесты проверки поведения в тестируемого устройства .

В этом смысле единица не обязательно является «методом в классе». Мне нравится определение юнита Роя Ошерова в «Искусстве юнит-тестирования» :

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

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


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

Он прав, но не так, как он думает.

Из вашего вопроса я понимаю, что вы являетесь «преданным тестером» в этом проекте.

Большое недоразумение в том, что он ожидает от вас написания модульных тестов (в отличие от «тестирования с использованием инфраструктуры модульного тестирования»). За написание тестов Ynit отвечает разработчик , а не тестировщик (в идеальном мире я знаю ...). С другой стороны, вы пометили этот вопрос TDD, что подразумевает именно это.

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

Еще раз подчеркну аналогию с автомобильной свалкой: сколько испытаний проведено с машиной в конце конвейера? Точно одно: он должен сам доехать до парковки ...

Дело здесь в следующем:

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


Для меня 100% покрытие модульных тестов - высокая цель, но даже если бы мы достигли только 50%, мы бы знали, что 100% из этих 50% были покрыты.

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

Вам не нужно 100% покрытие кода.

Но вам нужно 100% покрытие поведения. (Да, покрытие кода и поведение поведения как-то коррелируют, но ради этого они не идентичны.)

Если охват поведением менее 100%, успешный запуск набора тестов ничего не значит, так как вы могли изменить некоторые из непроверенных поведений. И вы будете замечены вашим клиентом на следующий день после выхода вашего релиза ...


Заключение

Несколько тестов лучше, чем никаких тестов. Без сомнения!

Но нет такой вещи, как иметь слишком много юнит-тестов.

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

Тимоти Тракл
источник
2

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

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

mrog
источник
4
«Кроме того, наш продукт имел некоторые зависимости, которые постоянно вносили серьезные изменения, которые означают для нас постоянное сопровождение испытаний». - Те тесты, которые вы говорите, требуют обслуживания, похожего на ценные, если ваши зависимости постоянно ломаются.
CodeMonkey
2
Это не проблема с тестами, а с организацией.
jwenting
2
@CodeMonkey Зависимости не сломались. Они обновлялись таким образом, что требовали изменений в нашем продукте. Да, тесты были ценными, но не такими ценными, как другие. Автоматизированные тесты наиболее ценны, когда эквивалентный ручной тест труден.
Мрог
2
@jwenting Да, это организационная проблема, а не проблема кода. Но это не меняет того факта, что было слишком много тестов. Неудачный тест, который нельзя исследовать, бесполезен, независимо от причины.
17
Что такое "SDET"?
Питер Мортенсен
1

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

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

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

wrschneider
источник
0

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

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

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

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

mmathis
источник