Как вы оцениваете качество ваших модульных тестов?

Если вы (или ваша организация) стараетесь полностью unit test вашего кода, как вы оцениваете успех или качество своих усилий?

  • Используете ли вы покрытие кода, на какой процент вы нацеливаете?
  • Вы находите, что такие философии, как TDD, имеют большее влияние, чем метрики?

Ответ 1

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

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

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

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

Кроме того, +1 для значения и ловушек тестового покрытия, уже упомянутых другими.

Ответ 2

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

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

Ответ 3

Если он может сломаться, он должен быть протестирован. Если он может быть протестирован, он должен быть автоматизирован.

Ответ 4

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

Или, как сказал Мартин Фаулер, анекдотические доказательства в поддержку модульных тестов и TDD являются ошеломляющими, но вы не можете измерить производительность. Подробнее о его bliki здесь: http://www.martinfowler.com/bliki/CannotMeasureProductivity.html

Ответ 5

Чтобы достичь полной уверенности в коде, вам нужны разные уровни тестирования: единицу, интеграцию и функциональность. Я согласен с приведенным выше советом, который гласит, что тестирование должно быть автоматизированным (непрерывная интеграция), и что модульное тестирование должно охватывать все ветки с помощью множества наборов данных кромки. Инструменты покрытия кода (например, Cobertura, Clover, EMMA и т.д.) Могут идентифицировать дыры в ваших ветких, но не в качестве ваших тестовых наборов данных. Анализ статического кода, такой как FindBugs, PMD, CPD, может идентифицировать проблемные области вашего кода, прежде чем они станут проблемой, и проделать большой путь к продвижению более эффективных методов разработки.

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

Однако программное обеспечение существует для удовлетворения потребностей бизнеса, поэтому существует также тестирование на соответствие требованиям. Это, как правило, более ручной процесс, основанный на функциональных (сетевых) тестах. По сути, вам нужно построить матрицу трассировки для каждого требования в спецификации и соответствующего функционального теста. По мере создания функциональных тестов они сопоставляются с одним или несколькими требованиями (например, "Логин как Fred", обновлять данные учетной записи для пароля, снова выходить из системы). Это касается вопроса о том, соответствует ли поставляемый результат потребностям бизнеса.

В целом я бы рекомендовал основанный на тестах подход к разработке, основанный на некотором вкусе автоматизированного модульного тестирования (JUnit, nUnit и т.д.). Для тестирования интеграции я бы рекомендовал иметь тестовую базу данных, которая автоматически заполняется в каждой сборке с помощью известного набора данных, который иллюстрирует общие варианты использования, но позволяет использовать другие тесты. Для функционального тестирования вам понадобится какой-то робот пользовательского интерфейса (SeleniumRC для Интернета, Abbot for Swing и т.д.). Метрики о каждом можно легко собрать во время процесса сборки и отобразить на сервере CI (например, Hudson) для всех разработчиков.

Ответ 6

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

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

Покрытие кода, например, глубоко вводит в заблуждение, потому что 100% -ый охват кода нигде не близок к полному охвату тестирования. Кроме того, такая цифра, как "80% -ый охват кода", столь же вводит в заблуждение без контекста. Если это покрытие находится в самых сложных битах кода и просто пропускает код, который настолько прост, что его легко проверить по глазу, то это значительно лучше, чем если бы охват был смещен в обратном порядке.

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

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

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

Ответ 7

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

Ответ 8

Я обычно делаю TDD, поэтому сначала пишу тесты, что помогает мне понять, как я хочу использовать объекты.

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

Помимо этого, и насколько это возможно, насколько возможно покрытие кода (иногда это невозможно получить на 100%), вы более или менее выполняете. Затем, если в будущем появятся какие-либо ошибки, вы просто убедитесь, что вы пишете тестовый пример для него, который выдает его первым, и пройдет, когда будет исправлено. Затем зафиксируйте как обычно.

Ответ 9

Мониторинг коэффициента покрытия кода может быть полезным, но вместо того, чтобы сосредоточиться на произвольной целевой скорости (80%, 90%, 100%?), я сочла полезным ориентироваться на положительную тенденцию с течением времени.

Ответ 10

Я думаю, что некоторые лучшие практики для модульных тестов:

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

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

Ответ 11

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

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

Ответ 12

  • В дополнение к TDD я обнаружил, что пишу более здравые тесты с BDD (например, http://rspec.info/)
  • Вечная дискуссия всегда состоит в том, чтобы высмеивать или не издеваться. Некоторые издевательства могут стать более сложными, чем те, которые он тестирует (что обычно указывает на плохое разделение проблем).
    • Поэтому мне нравится идея иметь метрику типа: сложность теста на сложность кода. или упрощено: количество тестовых строк на строки кода.