Как: освободить свой разум

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

Согласно Ларри Уоллу (1), первоначальному автору языка программирования Perl, у программиста есть три великих достоинства; Лень, нетерпеливость и высокомерие (http://threevirtues.com/):

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

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

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

Что касается тестирования, я переопределяю эти три достоинства следующим образом:

  1. Ленивость: вам нужны автоматизированные тесты, которые проверяют как повседневные, так и специфические для бизнеса аспекты вашей программы. Вы хотите иметь возможность рефакторинга в любой момент времени, без необходимости внимательно изучать весь существующий код, чтобы убедиться, что ваш рефакторинг ничего не сломает. После рефакторинга ваши тесты должны указать, все ли работает должным образом или необходимы дополнительные изменения для завершения рефакторинга. Пусть тесты станут вашим надежным помощником при разработке и рефакторинге.
  2. Нетерпеливость: вам нужен немедленный ответ о том, работают ли ваши последние изменения или нет. Вам нужны быстрые тесты, чтобы вы могли запустить весь набор тестов за секунды, выполняя их несколько раз в день локально по мере добавления кода или рефакторинга. Это один из ключей к тому, чтобы быть гибким программистом.
  3. Гордыня: самое обидное, что вы слышите, - это в вашем коде есть ошибка. Вы не воспринимаете это как комментарий к вашему коду, но воспринимаете это как личную атаку. Чтобы свести к минимуму это, как говорится, напишите комплексные тесты, чтобы никогда не писать об ошибках (https://www.teamten.com/lawrence/programming/dont-write-bugs.html). Для компьютера всегда лучше сказать вам, что в вашем коде есть проблема, чем для человека.

Что тестировать

Рассмотрим следующий код:

public void testEquality() {
    assertTrue(a.equals(a));
    assertNotEquals(a, b);
}

У этого теста есть несколько проблем:

  • Это слишком низкий уровень. Я не знаю, как этот тест соотносится с общими требованиями приложения.
  • Я не могу сказать, как работает класс для переменной «a» из этого теста.
  • Название теста не помогает мне понять, как работает этот класс.

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

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

Во-первых: разработчики, знакомые с кодовой базой (плохо)

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

Во-вторых: новые разработчики и существующие разработчики (хорошо)

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

Технически, достаточно одного из этих тестов, чтобы полностью охватить метод QualifiesForChildCredit. Но явно есть как минимум две ситуации, когда этот метод может быть вызван. Следовательно, у нас должно быть как минимум два теста для этого метода. Также обратите внимание на названия тестов. Они важны для любого разработчика, входящего в проект. Код теста также достаточно ясен, чтобы стать учебным пособием для новых разработчиков, чтобы увидеть, как работает служба соответствия требованиям.

Третье: владельцы продуктов, новые и существующие разработчики (лучше)

Хотя приведенные выше имена тестов очень ясны, вы можете выразить только определенную часть в одной строке, и в зависимости от вашего языка программирования вы можете столкнуться с ограничениями по длине имени функции / метода. По этой причине я считаю тесты BDD превосходными и рекомендую их в качестве метода тестирования по умолчанию, если вы только начинаете свой путь к тестированию. (Вы спросите, что такое BDD? Это расшифровывается как Behavior-Driven Development. Хорошее резюме можно найти здесь. Для целей этой статьи тесты BDD - это документация, которую могут прочитать оба человека. и компьютеры . Названия тестов объясняют, как работает приложение, на конкретных примерах).

Преобразовав вышеуказанный тест в формат BDD с использованием Ginkgo / Gomega (мои рекомендуемые мной библиотеки тестирования по умолчанию для Go), вы получите что-то похожее на это:

Обратите внимание, как с помощью этого метода я могу быть НАМНОГО более информативным, называя свои тесты. Называя тесты, вы должны иметь возможность сходить с ума при написании этих описаний. Ни в коем случае не ограничивайте себя. Еще важнее: при написании этих описаний перестаньте думать как инженер и думайте как нетехнический владелец продукта или деловой человек. Описания тестов должны быть похожи на бизнес-правила и должны быть понятны большинству. «Но деловые люди не будут читать эти тесты!», - скажете вы. Что ж, позвольте мне показать вам, что я получаю из этих типов тестов:

Это отчет, созданный на основе тестов BDD, который можно передать напрямую любому деловому человеку в компании (примечание: в ближайшем будущем я открою исходный код этого инструмента для Go / Ginkgo, так что смотрите my Страница GitHub для обновлений).

Реальная история: однажды я работал в компании, которая использовала PHP, и мы писали тесты BDD на PHPUnit. Я заметил, что одним из возможных отчетов была «гибкая документация» с указанием параметра --testdox-html. Я провел это в качестве эксперимента и передал отчет своему боссу (который, хотя и был хорошо осведомлен о бизнесе, но не был техническим специалистом). Через несколько минут он заметил, что одно из правил было неправильным! Используя текст описания, я смог быстро найти неправильный тест и исправить рассматриваемый код. Это настоящая ценность тестирования в стиле BDD!

Создавая отчет, подобный этому, вы реализуете следующий цикл разработки в своей компании:

Четвертое: все в компании (лучшие)

Если вы заметили на иллюстрации выше, «Бизнес-правила» отображаются дважды: правила, написанные Владельцем продукта, и отчет, созданный на основе наших модульных тестов. Что, если бы это были одни и те же? Именно это и есть настоящее тестирование в стиле BDD: и бизнес-специалисты, и инженеры совместно работают над документом спецификации, который используется разработчиками , который затем напишет тесты и код, удовлетворяющий спецификации. Файл спецификации может выглядеть следующим образом:

Самый популярный инструмент, используемый для обработки этих спецификаций (или файлов функций) - Огурец. Для Go активно разрабатывается официальный фреймворк Cucumber BDD.

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

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

Следующий

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

Спасибо за прочтение!