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

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

Наша отправная точка заключается в том, что у нас есть сборка непрерывной интеграции (CI), которая работает python -m unittest discover, как описано в документации. Начать работу с измерением покрытия юнит-тестами так же просто, как pip install coverage в Python (подробнее). Если у вас есть скрипт Python для запуска тестов, мы будем собирать данные о покрытии, выполнив следующее:

def run_tests():
""" Run the unit tests, collect coverage data and output an xml report.
    Adjust the cwd to match your test root folder.
"""
  subprocess.check_call(
    [
      "coverage",
      "run",
      "-m",
      "unittest",
      "discover",
    ],
    cwd="test",
  )
  subprocess.check_call(["coverage", "xml"], cwd="test")

Чтобы увидеть красивый HTML-отчет, используйте следующий код:

def open_html_coverage_report():
  subprocess.check_call(
    ["coverage", "html", "-d", "_coverage_data"], cwd="test"
  )
  subprocess.check_call(["open", "_coverage_data/index.html"], cwd="test")

После того, как вы потратили некоторое время на изучение отчета и составление картины вашего текущего покрытия, мы делаем первые шаги в установлении закона. Но самым добрым, самым нежным образом.

def check_coverage():
""" Generate a coverage report and fail if minimum coverage is not met. 
"""
  subprocess.check_call(["coverage", "xml", "--fail-under=85"], cwd="test")

Сейчас вы смотрите на один из двух результатов:

В первом сценарии все прошло успешно. Если это совершенно новый проект и вы устанавливаете забор перед тем, как взять щенка, поздравляем! Добавление этой проверки в новый проект — наименее болезненный способ. Также может случиться так, что вы, просто случайно, получили высокий уровень освещения проекта без отчетности, но это маловероятно.

Во втором сценарии вы видите такое сообщение:

Coverage failure: total of 56 is less than fail-under=85

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

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

На данный момент наша работа включает в себя создание данных о покрытии в формате XML, которые подключаемый модуль Cobertura будет использовать для создания красивого отчета в пользовательском интерфейсе Jenkins и установки статуса сборки. Начните с установки плагина, если у вас его еще нет. Вот ссылка: https://plugins.jenkins.io/cobertura/

Прежде чем прыгнуть в Jenkinsfile, нужно прояснить кое-что. Вы хотите, чтобы ваши сценарии имели локальную тестовую команду, которая использует параметр --fail-under, и тестовую команду CI, которая его не включает. В Jenkins мы всегда хотим создать отчет XML и запустить этап cobertura. Плагин Cobertura проверит уровень покрытия и завершит сборку (docs).

Вот как будет выглядеть наш файл Jenkins после запуска тестов:

cobertura autoUpdateHealth: false,
autoUpdateStability: false,
coberturaReportFile: '**/test/coverage.xml',
conditionalCoverageTargets: '70, 0, 0',
failUnhealthy: false,
failUnstable: true,
lineCoverageTargets: '80, 0, 85',
maxNumberOfBuilds: 0,
methodCoverageTargets: '80, 0, 0',
onlyStable: false,
sourceEncoding: 'ASCII',
zoomCoverageChart: false

Мы рассмотрим три наиболее важных параметра:

  1. coberturaReportFile должно соответствовать местоположению, в котором данные покрытия XML сохраняются командой coverage.
  2. failUnstable помечает сборку как нестабильную, когда она ниже порогового значения. Я предпочитаю считать сборку исправной, если ее не удается собрать, и нестабильной, если сборка завершается ошибкой на этапе после сборки.
  3. lineCoverageTargets содержит три числа, третье из которых является нашей целью. Вы можете углубиться в другие области применения, такие как условные выражения, но я оставлю это для вас.

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

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

Что такое хорошая цель? Без сомнения, это глубокая тема, но я раскрою ее практическим опытом. Это 85%. С проектами, которые начинаются с охвата, и с теми, которые представили его спустя годы, 85% разумны, беспрепятственны и полезны. Более высокое покрытие достижимо, но, как правило, бессмысленно. Каждый проект содержит какой-то шаблонный код и простой, сложный для тестирования код, который практически не имеет ценности. 85% допускают это без создания явных фильтров.

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