
Kover: плагин покрытия кода для Kotlin (Code Coverage plugin)
В конце декабря была официально выпущена версия Kotlin 1.6.0. В релизе не только были стабилизированы исчерпывающие выражения when, но и добавлены новые языковые функции и несколько очень хороших инструментов. В этой статье мы расскажем об одном из них: плагине Kover.
Проблема точного определения покрытия кода в Kotlin существует с самого первого релиза. В новой версии Kotlin эту проблему постарались решить с помощью Kover — нового плагина Gradle, который оценивает покрытие кода Kotlin, собранного компилятором Kotlin/JVM. Пока что плагин сырой, находится на ранней стадии разработки и создатели называют его экспериментальной функциональностью. Однако даже на этом этапе Kover имеет некоторую ценность для ваших проектов Kotlin.
Если вы хорошо знакомы с разработкой Java Virtual Machine (JVM), то, скорее всего, привыкли к файлам отчётов HTML/XML и обычно загружаете данные для отслеживания метрик с течением времени в такие системы как SonarQube или CodeCov. Kover полностью совместим с форматом JaCoCo, поэтому можно без проблем продолжать использовать их в полной мере и даже объединять, если у вас есть несколько проектов на разных языках JVM.
Давайте попробуем Kover и посмотрим, какие возможности он предоставляет.
Установка плагина
Если вы используете Gradle, то настройка для добавления плагина в проект будет очень простой. Вам нужно добавить плагин Kover в свой build.gradle(.kts) файл.
plugins {
...
id("org.jetbrains.kotlinx.kover") version "0.4.2"
...
}
Как только вы это сделаете, у вас будет доступ к нескольким новым задачам Gradle, которые можно найти в разделе проверки.
$ ./gradlew tasks
Verification tasks
------------------
koverCollectReports - Collects reports from all submodules in one directory.
koverHtmlReport - Generates code coverage HTML report for all module's test tasks.
koverReport - Generates code coverage HTML and XML reports for all module's test tasks.
koverVerify - Verifies code coverage metrics based on specified rules.
koverXmlReport - Generates code coverage XML report for all module's test tasks.
Запуск ./gradlew koverReport приведёт к созданию файлов покрытия в формате XML и HTML, точно так же, как если бы вы использовали для этого JaCoCo. После выполнения задачи новые отчёты можно будет найти в build/reports/kover. Открытие html/index.html предоставит доступ к информации в удобочитаемом формате.
О задачах Kover gradle
Как мы видим, при использовании плагина gradle taskinfo (который нужен для просмотра взаимосвязей между задачами gradle) не нужно специально запускать задачи kover, потому что они уже транзитивно вызываются другими задачами.
Мы сокращаем это здесь для краткости, но при запуске плагина taskinfo для задачи сборки видно, что запускается check, который запускает koverReport и koverVerify.
$ ./gradlew tiTree build
> Task :tiTree
:build
`--- :check
+--- :koverReport
+--- :koverVerify
`--- :test
BUILD SUCCESSFUL in 826ms
1 actionable task: 1 executed
Чтобы избежать замедления сборки для больших проектов или чтобы избежать сбоя формы сборки, можно эти цели при сборке пропустить:
./gradlew build -x koverVerify -x koverReport # skipping koverReport and koverVerify when building the project
Оцениваем KoverVerify
Одна из наиболее приятных фишек Kover, на наш взгляд, это koverVerify.
koverVerify позволяет выполнить сборку fail/pass на основе набора предопределенных правил. Существует несколько вариантов на выбор (общее количество пройденных строк, процент).
Простой пример может выглядеть так:
tasks.koverVerify {
rule {
name = "Minimal line coverage rate in percents"
bound {
minValue = 98
}
}
}
Это говорит koverVerify о том, что сборка завершится неудачно, если покрытие кода проекта упадет ниже 98%. Устанавливать ли жёсткие значения — тема для отдельного разговора, но, по крайней мере, мы знаем, что есть довольно простой способ это сделать.
Однако если вы хотите лучше ознакомиться с тенденциями (эти новые запросы снижают покрытие кода), то вам придётся полагаться на внешние инструменты, например, на CodeCov.
Загрузка информации о покрытии
Наличие покрытия кода в проекте само по себе приятно, но нам кажется, что гораздо интереснее наблюдать за тенденциями и использовать новую информацию в рабочем процессе.
Мы использовали в проекте GitHub Actions и CodeCov. Решение использовать в рабочем процессе две разные сборки объясняется просто: одна позволяет проверить, что покрытие кода отвечает определённым правилам, другая используется для создания и загрузки отчётов о покрытии, чтобы можно было с течением времени отметить тенденции и изменения.
Давайте начнём с наших правил:
name: Checking coverage with Gradle
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'adopt'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Check coverage metrics
run: ./gradlew koverVerify
Говорить здесь особо нечего: настроили типичную сборку для проекта Gradle, в конце запустили koverVerify.
Теперь перейдем к фактическому файлу действий по сборке:
name: Java CI with Gradle
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'adopt'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build -x koverVerify # skipping koverVerify to not fail if the coverage has lowered
- name: Upload coverage reports
uses: codecov/codecov-action@v2
with:
files: build/reports/kover/report.xml
Здесь тоже мало что происходит, но есть пара важных моментов:
- Мы пропускаем koverVerify в этой сборке. Основная причина этого проста: если проверка не удалась, будет сложнее увидеть, есть ли сбои в тестах или просто выгрузить отчёты о покрытии, чтобы увидеть, в чём заключаются основные проблемы.
- В конце сборки мы загрузили последнюю версию отчёта о CodeCov. Для публичных проектов нет необходимости настраивать ключи API.
При открытии Pull Request на GitHub можно получить следующий обзор:
Поскольку были запущены 2 разных файла действий, мы получили дополнительную информацию непосредственно от CodeCov о том, где следует работать лучше:
О IntelliJ «Запуск с покрытием кода»
Если вы хотите получить информацию о покрытии кода прямо из IntelliJ, сегодня это возможно без Kover. В конфигурации запуска выберите «Дополнительные параметры» и укажите там использование агентов IntelliJ или JaCoCo.
Затем вы можете выбрать, чтобы IntelliJ запускал ваши тесты с опцией покрытия.
Подробнее прочитать о покрытии кода можно на сайте IntelliJ
Важно знать, что при запуске покрытия кода из IntelliJ оно, по определению, не является частью сборки и работает только в рамках вашей системы.
Почему бы не запустить JaCoCo?
Возможно, у вас возник вопрос, зачем на самом деле нужен Kover. В конце концов, Kotlin работает на JVM и раньше можно было без проблем запускать JaCoCo непосредственно в своих проектах Kotlin. На YouTube есть видео, содержащее подробный ответ на ваш вопрос, но если вкратце, то поддержка конкретной функции Kotlin является недостаточной при запуске инструмента в байт-коде. Думаем, любой, кто пытался запустить статический анализ кода в байт-коде, знает, о чём речь.
В заключение
Мы считаем хорошей новостью то, что Kotlin 1.6.0 фокусируется не только на экосистеме, но и на инструментах. Наличие специального инструмента покрытия кода имеет большое значение для Kotlin, и нам кажется, что он заполнит пробел во многих командах.
Текущий плагин довольно прост, но в нём есть все необходимые опции. И хотя проект ещё находится на ранней стадии, мы не столкнулись ни с какими пугающими проблемами и думаем, что у него большое будущее.
