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

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

Об их скорости

Позвольте мне получить это прямо. Вы хотите, чтобы ваши тесты были молниеносными. Почему? Потому что, когда они медленные, у вас нет стимула их запускать. И поверьте мне, вы хотите запускать их как можно чаще. Вы можете думать об этом как о запуске их при каждом нажатии ctrl+s. Хорошо, хорошо, это было преувеличением, но теперь вы понимаете, о какой частоте я говорю.

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

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

Об их детализации

Крайности следующие: слишком грубым является один тестовый класс для всего приложения, слишком тонким является один тестовый класс на класс продукции.

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

Однако ситуация «слишком хорошо» рассматривается некоторыми как идеальный случай. Они называют это модульными тестами. Мне они не особенно нравятся, потому что они склонны прижимать слишком маленькую часть исходного кода: в идеале ваши рабочие классы должны быть 30–50 LOC, но не более 100. Вы можете себе представить, какая это нагрузка ломать эти тесты с каждым внесенным изменением, каждый раз приспосабливая их. Такая тонкая детализация также препятствует рефакторингу, такому как метод перемещения, встроенный класс и т. д. А рефакторинг — одна из самых важных дисциплин, которыми нужно заниматься.

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

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

Об их изоляции

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

Об их длине (в пересчете на LOC)

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

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

О порядке их исполнения

Тесты, требующие определенного порядка выполнения, — мусор. Это означает, что между ними есть какие-то помехи. Лучший способ потратить 2 или 3 дня на занятие по тестированию — попытаться выяснить, почему тесты выполняются только в том порядке, в котором они написаны; почему одни бегают одни, а не вместе с другими или наоборот. Чистый ад. Чтобы избежать этого, не позволяйте себе расслабляться и рандомизируйте их порядок выполнения с самого начала.

О моках

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

О закладывании в них логики

Вложите в свои тесты как можно меньше логики. Условные выражения и циклы, как правило, плохая идея — есть шанс, что вы напишете тест с ошибками. И иметь вторичные тесты для проверки ваших первичных тестов — это излишество, верно?

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

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

Об их покрытии

Вы думали, что это будет на высоте, не так ли? Ну, это чрезмерно злоупотребляемая метрика, которая почти ничего не говорит вам о ваших тестах и ​​рабочем коде. В то время как отсутствие покрытия, очевидно, плохо, полное покрытие ничего не значит. Учтите это — я могу легко написать тесты, которые обеспечивают 100% покрытие, ничего не тестируя — просто протестируйте все пути выполнения и ничего не утверждайте в конце. Должен ли он придать мне уверенности в моем коде: абсолютно нет. Дает ли это моему менеджеру уверенность в моем коде: да, во многом. Короче говоря, не слишком полагайтесь на покрытие кода и никогда не устанавливайте порог покрытия в CI/CD. На самом деле, когда я думаю об этом, кажется, что покрытие кода так популярно, потому что это единственный показатель, который можно измерить. [Грустные звуки.]

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