Как проверить, что комит с новым кодом покрыт тестами? Как проконтролировать, что тесты будут написаны? Какой тип метрики покрытия выбрать для анализа?
Можно использовать простое средство, настроить Build Validation, проверка будет стартовать при каждом Pull Request в выбранную для валидации ветку и включать шаги проверки Code Coverage, останавливая сборку если процент покрытия снизился. Такой подход называют "Quality Gate".
Quality Gate — это принудительная мера или метрика, встроенная в Pipeline, которой должно соответствовать программное обеспечение, прежде чем оно сможет перейти к следующему шагу. Эта мера обеспечивает соблюдение определенных правил, метрик или практик, которым должен следовать код, чтобы предотвратить проникновение кода низкого качества в разрабатываемое ПО.
Quality Gate можно легко настроить в Azure Pipelines. Рассмотренные в статье шаги сборки и анализа покрытия универсальны и могут быть использованы в любой CI/CD системе, такой как Jenkins, TeamCity etc.
Для того что бы легко протестировать решение понадобится:
учебный проект: https://github.com/devops-stack/eShopOnContainers
создать учетку в Visual Studio или войти с GitHub экаунтом: https://azure.microsoft.com/en-us/products/devops/pipelines
Подготовка и запуск проекта
Для наглядности, лучше всего начать с практического примера. В бесплатной подписке вы можете склонировать репозиторий и создать свой pipeline, процесс создания и запуска простой и займет 3 минуты. В бесплатной подписке Azure DevOps (VisualStudio) есть доступный агент сборки, поэтому есть возможность быстро увидеть все самому:
Зарегистрируйтесь или зайдите с помощью GitHub экаунта (процесс регистрации максимально легкий): https://azure.microsoft.com/en-us/products/devops/pipelines и нажмите кнопку "Start Free".
Затем нажмите "+ New Project", задайте имя проекта в поле "Project Name" и нажмите "Create". После создания перейдите в раздел "Repos", в разделе "Import a repository" нажмите "Import", скопируйте ссылку https://github.com/devops-stack/eShopOnContainers в поле "Clone URL" и нажмите "Import".
После клонирования, переходите в раздел "Pipelines", жмите кнопку "Create Pipeline", выбирайте "Azure Repos Git", затем выбирайте созданный только что репозиторий и жмите на "Existing Azure Pipelines YAML file". Выберите ветку "main", скопируйте "путь к пайплайну "src/Services/Catalog/azure-pipelines.yml", затем "Continue" и нажмите "Run". Ваша сборка готова!
Можно, так же, просто перейти и посмотреть настроенный пайплайн и код (понадобится учетная запись Visual Studio или GitHub, процесс регистрации максимально простой).
Пример проекта PROD Grade уровня
В статье используется проект разработанный командой Microsoft, это, готовый для использования, интернет магазин, разработанный на .NetCore, с использованием микросервисной архитектуры и соблюдением стандартов проектирования и разработки. А так же добавлены Unit Tests и Functional Tests поэтому магазин удобно использовать для демонстрации и практических примеров (я попытался рассказать про эту разработку подробнее). Проект удобно разворачивается локально, в Kubernetes, Docker Compose или Azure Kubernetes Service. Так же в репозитории прилагается несколько книг полностью покрывающих цикл разработки и эксплуатации, очень удобных для изучения технологии с разных сторон QA, Development, DevOps. В статье будет использоваться код и тесты сервиса "Catalog" этого интернет магазина.
Для упрощения примера и наглядности, будет протестирован только один из сервисов проекта, а в пайплайне используются прямые пути к файлам проекта, тогда как в реальных средах чаще используются переменные. Для анализа покрытия репозитория с большим количеством сервисов процесс немного усложняется. Во второй статье будет рассмотрен универсальный шаблон для разных сервисов c использованием переменных.
Шаги пайплайна с Code Coverage и Build Quality Checks
Подготовка и проверка покрытия состоит из нескольких простых шагов, посмотреть код полностью готового пайплайн можно по ссылке в форке репозитория. Дальше предоставляется описание шагов с небольшими комментариями.
Tasks #1 и #2: Restore and Build
На первых двух задачах выполняется обновление зависимостей и сборка сервиса (во всей статье используется ветка main):
- task: DotNetCoreCLI@2
displayName: Restore
inputs:
command: restore
projects: 'src/Services/Catalog/Catalog.API/Catalog.API.csproj'
nugetConfigPath: 'src/NuGet.config'
- task: DotNetCoreCLI@2
displayName: Build
inputs:
command: build
projects: 'src/Services/Catalog/Catalog.API/Catalog.API.csproj'
arguments: '--configuration debug'
Task #3 Запуск тестов и формирование коллекции данных
Для сбора данных об объема протестированного кода будем использовать сборщик Coverlet с помощью параметра --collect "XPlat Code Coverage"
. Этот ключ используется для Linux энвайрментов. Это межплатформенный вариант, основанный на .NET CLI, который отлично подходит для систем сборки, в которых недоступен MSBuild. В среде Windows можно использовать параметр --collect "Code Coverage"
Для вычисления процента кода к которому обращаются тесты будет использоваться Cobertura.
- task: DotNetCoreCLI@2
displayName: 'Execute unit tests'
inputs:
command: 'test'
arguments: '--configuration debug --collect:"XPlat Code Coverage" \
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=cobertura'
publishTestResults: true
projects: 'src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj'
для успешного выполнения этого шага в csproj файл должна быть добавлена зависимость:
<PackageReference Include="coverlet.collector" Version="6.0.0" />
Task #4 Публикация собраной статистики
Шаг "Publish Code Coverage Results" понадобится для заключительного этапа, для того что бы подготовить артефакт в формате Cobertura и разметить его в нужной локации.
- task: PublishCodeCoverageResults@1
displayName: 'Publish code coverage report'
inputs:
codeCoverageTool: 'Cobertura'
summaryFileLocation: '$(Agent.TempDirectory)/**/coverage.cobertura.xml'
После выполнения шагов 3 и 4 станут доступными закладки "Tests" и "Code Coverage".
На закладках отображается информация о выполнении тестов и детальная статистика "Code Coverage" соответственно:
Task #5 Настройка Build Quality Checks
Шаг "Build Quality Checks" позволяет добавить "Quality Gate" в пайплайн. Как и предыдущие этапы, этот шаг достаточно простой, но является "вишенкой на торте", мы будем использовать политику ветки Azure DevOps для того что бы настроить остановку билда если порог покрытия снизился. Это защитит проект от снижения уровня покрытия кода тестами. "Build Quality Checks" при первом запуске анализирует покрытие кода и формирует Baseline - базовое значение, от которого будет считаться снижение покрытия кода, это просто процент покрытия предыдущего успешного билда. Вы можете так же задать требуемый процент покрытия.
- task: BuildQualityChecks@9
displayName: 'Check build quality'
inputs:
checkCoverage: true
coverageType: lines
Пример с фиксированным процентом покрытия установленным вручную:
steps:
- task: BuildQualityChecks@9
displayName: 'Check build quality'
inputs:
checkCoverage: true
coverageFailOption: fixed
coverageThreshold: 70
Сode Сoverage и Branch Coverage
Две самых популярных метриках покрытия — code coverage и branch coverage. В заключительном шаге "Build Quality Checks" по умолчанию выбран анализ c Сode Сoverage метрикой. Проще начинать внедрение метрики с контролем снижения процента покрытия сравнивая с предыдущей сборкой и вырабатывать подходящий процент исходя из опыта разработки требований проекта. Повторюсь, если вы только начали работать с метриками, лучше начинать от простого, билб за билдом анализировать как именно формируется процент покрытия кода вашего проекта и не делать жесткие требования к покрытию когда.
Branch coverage дает более глубокий анализ, чем code coverage. Вместо использования количества строк кода, эта метрика ориентируется на таки структуры как команды if и switch и немного усложняет разработку тестов.
Visual Studio Test оценивает, сколько строк кода, а также сколько блоков кода было покрыто тестами. Другие инструменты, такие как Cobertura, используют другие типы покрытия, такие как Branch Coverage, аналогичное Block Coverage.
Quality Gate: настройка политики ветки Azure DevOps
Сделаем простую настройку для Quality Gate в Azure Pipelines:
В Azure Pipelines перейдите в раздел "Repos" -> "Branches", наведите курсор на ветку "main" и в крайнем правом углу выберите появившуюся кнопку с тремя точками и затем "Branch Policies".
В разделе "Build Validation" нажмите "+", проверьте что в поле выбран пайплайн который мы создавали в начале статьи и нажмите "save".
Давайте проверим подготовленное решение:
Создайте новую ветку от main, в разделе "repos" > "Branches" нажмите "New Branch", задайте имя ветки и убедитесь что в поле "Based on" выбрана ветвь "main".
В разделе "Branches" перейдите в созданную ветку (воспользуйтесь поиском), откройте файл "/src/Services/Catalog/Catalog.UnitTests/Application/CatalogControllerTest.cs" и удалите весь код в методе "Get_catalog_items_success()", сам метод и две скобки {} оставьте (см. криншот ниже).
Затем нажмите "Commit" > "Commit" и появившуюся кнопку "Create a pull request". Заполните поле "Title" и нажмите "Create"
Теперь ветвь main защищена пайплайном который мы разработали. При попытке сделать PR в ветку запустится пайплайн и в случае снижения процента покрытия кода, остановится с сообщением, что процент покрытия кода снизился относительно последней проверки. И настроенная политика ветки не даст завершить pull request.
На скриншоте выше видно что проверка обязательна при PR в ветку с включенной политикой "Build Validation". Появилось сообщение о снижении покрытия кода и билд остановился. Нажав на название пайплайна, можно посмотреть подробности.
Выполнение Pull Request не обязательно "останавливать". Если вы только формируете требования подход к тестированию, удобно настроить опциональную проверку и не останавливать билд. Так же в Azure DevOps есть возможность выдать права на изменение политики ветки определенным людям. Таким образом когда подход к тестированию, метрики и процент покрытия будет выработан, если есть потребность можно жестко регламентировать требования к покрытию тестами.
В следующей статье будет добавлен важный этап настройки template pipeline для репозитория с большим количеством сервиса. Это нужно на случай если сервисы вашей платформы или веб приложения разрабатываются различными командами. Тогда Quality Gate пайплайн не должен блокировать разработку других сервисов.
Дополнительные ресурсы:
Отличная книга: "Принципы юнит-тестирования Хориков В."
Build, test, and deploy .NET Core apps
Quality Gates in Testing - Powerful but underused by Gipil Quddus
Configuring Test Reports and Code Coverage
Build Quality Checks repo and readme
Coverlet is a cross platform code coverage framework for .NET