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

23

Стоит ли при написании модульных тестов тратить дополнительное время на то, чтобы код имел хорошее качество и удобочитаемость?

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

m3th0dman
источник
5
Читаемость и ремонтопригодность должны быть в центре внимания модульного тестирования.
Е.Л. Юсубов
2
Тесты тоже код!
Грант Пэйлин
Он по-прежнему является частью вашего проекта, даже если он не доставляется клиентам. Относитесь к этому соответственно.

Ответы:

11

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

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

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

  • Если ваши тесты нарушают Закон Деметры в их разделах Assert (т.е. вы проверяете значение чего-то, что глубоко вложено в граф зависимостей тестируемого объекта), возможно, это действительно интеграционные тесты, а не модульные тесты. Другими словами, если в TestA вы утверждаете, что ABCD что-то равно, возможно, вы пытаетесь проверить D и A, а не просто A.

Кстати, когда вы говорите

Я часто нарушаю Закон Деметры, чтобы быстрее писать и не использовать так много переменных.

Вы должны знать, что написание

var grab = myDependency.Grab;
var something = grab.Something;
var very = something.Very;

very.Deep();

на самом деле не лучше Деметры мудрее, чем

myDependency.Grab.Something.Very.Deep();

если ты это имел ввиду

guillaume31
источник
47

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

  • Они потребуют обслуживания, как и любой другой код.
  • Модульные тесты являются одним из лучших источников документации для вашей системы и, возможно, наиболее надежной формой. Они должны действительно показать:
    • Намерение: «каково ожидаемое поведение?».
    • Использование: «как я должен использовать этот API?».
  • Они потребуют отладки, как и любой другой код.

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

vaughandroid
источник
22

Да, это важно Существует несколько причин, по которым модульные тесты должны соответствовать стандарту, аналогичному другому коду:

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

  • Модульные тесты тоже могут содержать ошибки. И ошибки более заметны, когда код хорошо написан.

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

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

Бенджамин Клостер
источник
12

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

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

чокнутый урод
источник
1

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

Это означает:

  • Извлечь сборку тестовых данных в классы компоновщика.
  • Извлечение нескольких утверждений в отдельные методы утверждений.
  • Будьте очень точны в названии. Assert.That(x4, Is.EqualTo(y16*2*SOME_VALUE), ASS_ERR_TXT_56)имеет очень мало смысла для большинства читателей.

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

Morten
источник
1

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

Выполните одно из следующих действий в своих тестах:

  • Дубликат кода
  • Уменьшить читаемость
  • Тесная связь
  • Временная связь
  • Высокая цикломатическая сложность (много зависимостей)

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

Относитесь к своим тестам, как вы предложили, и вы в конечном итоге пожалеете об этом. Вы, вероятно, даже придете к ложному выводу, что «TDD не работает».

Ям Маркович
источник
0

Это зависит от того, являются ли эти юнит-тесты «временными» или нет. Если

  1. Тест будет часто использоваться;

  2. Разработчики должны работать с юнит-тестами, написанными другими разработчиками;

  3. Большая часть тестирования выполняется модульными тестами

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

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

superM
источник
(1) модульные тесты никогда не являются временными (2), даже если они для вас самих, за один месяц (или больше) вы не будете помнить все детали, поэтому важно делать это правильно - даже для себя
BЈовић