Применяется ли YAGNI и при написании тестов?

Когда я пишу код, я пишу только те функции, которые мне нужны, когда они мне нужны.

Этот подход также применим к написанию тестов?

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

11 ответов

Решение

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

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

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

В последнем случае я менее способен дать вам окончательный ответ. Вы, безусловно, хотите, чтобы ваши тесты оставались СУХИМЫМИ - не пишите тест, который просто повторяет другой тест, даже если он содержит другие данные. В качестве альтернативы, вы не можете обнаружить потенциальные проблемы проектирования, если вы не используете крайние случаи ваших данных. Простым примером является метод, который вычисляет сумму двух целых чисел: что произойдет, если вы передадите его maxint как оба параметра? Если у вас есть только один тест, то вы можете пропустить это поведение. Очевидно, это связано с предыдущим пунктом. Только вы можете быть уверены, когда тест действительно необходим или нет.

Да, ЯГНИ абсолютно относится к написанию тестов.

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

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

Кроме того, я бы написал тесты для проверки ввода? Абсолютно. Тем не менее, я бы сделал это в точку. Допустим, у вас есть функция с 3 параметрами, которые являются целыми, и она возвращает значение типа double. Сколько тестов вы собираетесь написать вокруг этой функции. Я бы использовал YAGNI, чтобы определить, какие тесты принесут вам хороший ROI, а какие бесполезны.

Напишите тест, как вам нужно. Тесты кодовые. Написание нескольких (изначально неудачных) тестов заранее нарушает цикл TDD красный / исправление / зеленый и усложняет идентификацию действительных отказов по сравнению с неписанным кодом.

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

Это дает следующие преимущества:

  1. Ваши тесты помогают определить функциональность этого этапа.
  2. Вы знаете, когда прошли этот этап, потому что все ваши тесты пройдены.

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

Так что нет. ЯГНИ не включает тесты:)

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

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

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

Мягкое Обновление

Должен заметить, что я прихожу с другой точки зрения, чем многие здесь. Я часто нахожу, что пишу код в стиле библиотеки, то есть код, который будет повторно использоваться в нескольких проектах для разных клиентов. В результате я, как правило, не могу с уверенностью сказать, что определенных вариантов использования просто не произойдет. Лучшее, что я могу сделать, это либо документ, что они не ожидаются (и, следовательно, может потребовать обновления тестов позже), либо - и это мое предпочтение:) - просто написание тестов. Я часто нахожу вариант № 2 для более пригодного для повседневного использования просто потому, что у меня гораздо больше уверенности, когда я повторно использую компонент X в новом приложении Y. И уверенность, на мой взгляд, то, что автоматическое тестирование является все о.

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

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

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

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

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

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

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

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

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

Я часто нахожу себя пишущим тесты, TDD, для случаев, которые я не ожидаю, что нормальный поток программ вызовет Подход "фальсифицируй, пока сделаешь" заставляет меня начинать, как правило, с нулевого ввода - достаточно, чтобы иметь представление о том, как должен выглядеть вызов функции, какие типы будут иметь ее параметры и какой тип будет вернуть. Чтобы было ясно, я не просто отправлю null в функцию в моем тесте; Я инициализирую типизированную переменную для хранения нулевого значения; таким образом, когда Eclipse Quick Fix создает функцию для меня, она уже имеет правильный тип. Но нередко я не ожидаю, что программа, как правило, отправит нуль в функцию. Так что, возможно, я пишу тест, который я AGN. Но если я начну со значений, иногда это слишком большой кусок. Я одновременно разрабатываю API и продвигаю его реальную реализацию с самого начала. Итак, начиная медленно и притворяясь, пока я делаю это, иногда я пишу тесты для случаев, которые я не ожидаю увидеть в рабочем коде.

Другие вопросы по тегам