Действительно ли модульные тесты используются в качестве документации?

22

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

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

Итак, вопрос: когда юнит-тесты используются в качестве документации? Когда комментарии не охватывают все? Авторы, расширяющие источник? И что они раскрывают, что может быть полезным и актуальным, что сама документация не может раскрыть?

Стейн
источник
4
Никогда не задумывался об использовании модульного теста прямо как документация Я думаю, что юнит-тесты часто не читаются, потому что многие разработчики не тратят время на их написание.
SuperM
10
Комментарии могут быть неправильными.
2
Я знаю, что вы спрашиваете конкретно о модульных тестах, но я бы также отметил, что интеграционные / системные тесты также являются действительно полезной документацией, просто на другом уровне
jk.
3
Я видел юнит-тесты, которые лучше всего охарактеризовать как «юнит-эксперименты». Их зависимость от внешних факторов была настолько сильна, что делала их практически бесполезными. Они были также очень неясны. (Да, у меня есть долгосрочная цель реорганизовать их, чтобы они стали лучше, но я занимаюсь и другими вещами…)
Донал Феллоуз
4
Модульные тесты @Ant вызывают реальный код и документируют ожидаемый ответ и сравнивают его с фактическим ответом. Является ли вызванный код правильным или нет, дело не в этом - тесты документируют, как его вызывать.

Ответы:

17

Они НЕ АБСОЛЮТНАЯ справочная документация

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

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

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

  • Тесты могут быть неполными:
    • API изменился и не был протестирован,
    • Человек, который написал код, написал тесты для самых простых методов для тестирования сначала вместо самых важных методов для тестирования, а затем не было времени, чтобы закончить.
  • Тесты могут быть устаревшими.
  • Тесты могут быть закорочены неочевидными способами и фактически не выполнены.

НО они ПОЛЕЗНО ПОЛЕЗНЫМ дополнением к документации

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

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

Кроме того, если они написаны с использованием стиля BDD , они дают довольно хорошее определение контракта класса . Откройте вашу IDE (или используйте grep), чтобы увидеть только имена методов и таду: у вас есть список поведения.

Регрессиям и ошибкам тоже нужны тесты

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

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

haylem
источник
Могу ли я спросить, почему я был понижен? Что вас там бесит или с чем вы не согласны?
Хайлем
2
Лучшая часть вашего аргумента (IMO) написана наименьшим шрифтом - лучший способ понять код - это иметь читаемый код. Я бы изменил это на «читаемый и рабочий код», но я согласен. Затем, если вы снова посмотрите на модульные тесты - выполняющиеся тесты - это рабочий код (и, как и весь код, должен быть читаемым), так что на самом деле это довольно хорошая (если часто слишком локальная) документация, когда она выполнена хорошо.
Йорис Тиммерманс
@MadKeithV: спасибо. Я обновил для «читаемый и рабочий код» и поднял этот бит выше.
Хайлем
11

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

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

Йорис Тиммерманс
источник
5

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

Они заменяют документацию? Нет.

Являются ли они полезным дополнением к документации? Да.

Сардатрион - Восстановить Монику
источник
4

Я вижу юнит-тесты как:

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

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

Дэвид Андреолетти
источник
3

Я собираюсь ответить на ваш вопрос, задав вам другой.

Как часто при работе с новым API / подпрограммой вы запускаете справку, чтобы найти пример кода того, что вы пытаетесь использовать? Если вы не переключитесь на Google для онлайн-поиска примеров кода?

Именно тогда вы будете использовать модульные тесты в качестве документации.

  • На самом деле модульные тесты могут быть немного более строгими, чем обычные примеры кода, потому что у вас должно быть несколько тестов (примеров).
  • Надеемся, что ваши юнит-тесты иллюстрируют правильное использование. Например, они четко показывают все существенные зависимости либо через обычные объекты, либо через фиктивные объекты. (В противном случае они не особенно хороши для юнит-тестов.)
  • ПРИМЕЧАНИЕ. Если ваши комментарии или «обычная документация» содержат примеры кода, вы фактически нарушаете принципы СУХОЙ. И эти примеры кода могут легко стать некорректными со временем, тогда как при регулярно выполняемых модульных тестах вероятность этого значительно меньше.
  • Если юнит-тесты тщательные (обычно это большое условие ), то они должны предоставить дополнительную информацию:
    • Все известные крайние случаи четко проиллюстрированы.
    • Все ожидаемые исключения, которые могут быть выброшены.
    • Все ранее найденные ошибки (это, вероятно, более полезно при расширении тестируемого модуля, чем при написании нового клиента для модуля).
    • Все основные бизнес-правила, связанные с подразделением. (если есть)

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

  • Я бы рискнул предположить, что часто сами тесты недостаточно хорошо написаны для этой цели. Другие ответы уже ссылались на тесты, которые:
    • Неполное.
    • Смешение. (Я видел тестовые случаи, которые не вызывают тестируемый метод напрямую - вы проходите 3/4 уровня вглубь стека вызовов до его вызова, и предварительные условия для вызова метода разбросаны по разным местам в сложной иерархии классов. )
    • Устаревшие. (обычно тесты должны проваливаться, когда они устаревают, но это не всегда так).
  • Обычно в рабочем коде уже есть множество примеров использования, когда возникает необходимость в этом примере.
  • Тестируемый модуль написан настолько хорошо (самодокументируется), что методам не нужны примеры. Хотел бы я!
  • По моему опыту, как программиста, мы очень заинтересованы в глубоком конце и RTFM в следующий вторник ...
  • Документация и комментарии, нарушающие принцип СУХОЙ.
разочарованный
источник
2

TL; DR модульные тесты и комментарии к API дополняют друг друга - некоторые вещи лучше всего описать в коде, а другие - в прозе.

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

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

Пример: у вас есть метод m, (a, b)который выполняет определенные вычисления. Из-за требований обратной совместимости, он должен входить в особый случай a=0и a=-1, но только если bNULL. Поместить это в комментарий сложно, многословно и, скорее всего, оно устареет, если позднее требование будет удалено.

Если вы сделаете несколько юнит-тестов, которые проверяют поведение m(0, NULL), m(-1, x)вы получите несколько преимуществ:

  • Описание правильного поведения понятно, недоразумения уменьшены
  • Люди не могут игнорировать требования при изменении кода, в отличие от комментария
sleske
источник
но для вашего примера, если такое поведение вообще не задокументировано в комментарии, пользователь может получить неожиданные результаты для этого граничного случая. Что не совсем хорошо.
Stijn
@stijn: правда. В этом случае, вероятно, лучше всего было бы кратко упомянуть об особом случае в документах, а также о модульных тестах на грязные детали.
Слёске