2 мар. 2021 г.
Всем привет! Сегодня хотел бы рассказать о настройке анализа покрытия кода тестами для PHP(Symfony) проекта. И последующую интеграцию с Github Actions.
Анализ покрытия тестами нужен в первую очередь для определения того, насколько качественно написаны тесты и насколько они реально тестируют код. Подробнее об анализе покрытия кода.
Изначально настраивал для этого блога. Но затем, для большей наглядности, также настроил для одного из открытых проектов - placeholder-service.
Для начала нам понадобится Xdebug. Его можно установить по-разному, в зависимости от окружения. Установка в docker:
FROM php:8.0-fpm
# ... #
RUN pecl install xdebug
RUN docker-php-ext-enable xdebug
Установка локально на Linux Ubuntu 20.04:
sudo apt install php8.0-xdebug
Чтобы сгенерировать отчет о покрытии тестами, нужно при запуске phpunit добавить дополнительные параметры.
./bin/phpunit --coverage-html coverage --coverage-clover coverage.xml
Для сохранения html отчета в папку coverage: --coverage-html coverage
.
Для сохранения xml отчета: --coverage-clover coverage.xml
.
Он нам понадобится для генерации значка о покрытии. Либо для загрузки статистики в сторонний сервис.
Чтобы не вводить каждый раз вручную, можно добавить скрипт в composer.json
. И запускать таким образом composer test
.
{
...
"scripts": {
...
"test": [
"./bin/phpunit --coverage-html coverage --coverage-clover coverage.xml"
],
...
}
...
}
В результате получим примерно такой отчет. Здесь виден общий процент покрытия и статистика по каждому файлу. Также видно, какие конкретно строчки кода тестами не покрыты. Можно проанализировать и написать соответствующие тесты.
Для создания значка покрытия можно использовать библиотеку PHPCoverageBadge. Установка библиотеки:
composer require --dev jaschilz/php-coverage-badger
Генерация значка на основании статистики покрытия:
vendor/bin/php-coverage-badger coverage.xml .github/badges/coverage.svg
Чтобы не вводить каждый раз вручную, можно добавить скрипт в composer.json
. И запускать таким образом composer update-badges
.
{
...
"scripts": {
...
"update-badges": [
"vendor/bin/php-coverage-badger coverage.xml .github/badges/coverage.svg"
],
...
}
...
}
Затем добавим значок в README.md
. В случае приватного репозитория этот способ не работает, но можно вынести картинку на web-сервер.
...
![Code Coverage](https://raw.githubusercontent.com/antonshell/placeholder-service/master/.github/badges/coverage.svg)
Настроим анализ покрытия тестами для Github Actions. Таким образом, можно смотреть покрытие тестами для каждого Pull Request, а также проверять, что покрытие кода выше определенного процента. При установке PHP нужно добавить Xdebug:
# https://github.com/shivammathur/setup-php (community)
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
coverage: xdebug
tools: composer:v2
extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite, dom, filter, gd, iconv, json, mbstring, pdo, xdebug
env:
update: true
Для начала добавим проверку уровня покрытия в .github/workflows/tests.yml
.
Проверяем, что общее покрытие кода тестами больше или равно 40%.
Для проверки используем coverage.xml
файл, сгенерированный при запуске тестов.
- name: Check test coverage
id: test-coverage
uses: johanvanhelden/gha-clover-test-coverage-check@v1
with:
percentage: "40"
filename: "coverage.xml"
Также хотелось бы видеть сам отчет о покрытии тестами в каждом Pull Request. Для этого можно было бы попытаться использовать хранилище артефактов. Либо можно использовать сторонний сервис codecov.io (платный). Либо можно использовать собственный внешний Web-сервер.
Для private репозитория нужно обязательно защитить Web-сервер с помощью basic auth или другим способом!
## —— Upload tests coverage report to remote server
- name: Extract branch name
shell: bash
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
id: extract_branch
- name: Print branch name
shell: bash
run: echo ${{ steps.extract_branch.outputs.branch }}
- name: Create directories for reports
uses: appleboy/ssh-action@master
env:
BRANCH: ${{ steps.extract_branch.outputs.branch }}
FILES_PATH: ${{ secrets.GA_FILES_PATH }}
with:
envs: BRANCH,FILES_PATH
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
passphrase: ''
script: mkdir -p $FILES_PATH/$BRANCH/coverage
- name: Uploads reports to server
uses: appleboy/scp-action@master
with:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
passphrase: ''
rm: true
source: "coverage"
target: ${{ secrets.GA_FILES_PATH }}/${{ steps.extract_branch.outputs.branch }}/coverage
Извлекаем название ветки, подключаемся по SSH к Web-серверу и создаем нужную директорию.
Затем сохраняем html отчет в эту директорию. Пришлось добавить двойную вложенность /coverage/coverage
т.к. в противном случае удаляется все содержимое branch папки.
Также нужно добавить в хранилище Github Secrets переменную GA_FILES_PATH
.
Затем сохранить в нее путь до директории с файлами на Web-сервере, например: /var/www/files/placeholder-service
.
Также нужно добавить переменные REMOTE_HOST
, REMOTE_USER
, SERVER_SSH_KEY
для доступа к серверу по SSH.
Подробнее об этом в предыдущей статье или
в этом руководстве.
После успешного выполнения отчет будет доступен по ссылке: http://files.antonshell.me/github-actions/placeholder-service/configure_code_coverage/coverage/coverage.
Теперь нам нужно отображать сгенерированный отчет на странице Pull Request.
Сделать это напрямую не получится, однако мы можем добавить ссылку на сгенерированный отчет.
Для этого создадим новое workflow.github/workflows/pull_request_comments.yml
, которое будет добавлять комментарий со ссылкой на отчет.
name: Pull request comments
on:
pull_request:
jobs:
pull_request_comments:
runs-on: ubuntu-20.04
steps:
- name: Extract branch name
shell: bash
run: echo "##[set-output name=branch;]$(echo ${GITHUB_HEAD_REF})"
id: extract_branch
- name: Print branch name
shell: bash
run: echo ${{ steps.extract_branch.outputs.branch }}
- name: Add test coverage report comment
uses: mshick/add-pr-comment@v1
with:
message: |
Test coverage report: [http://private.antonshell.me/github-actions/antonshell/${{ steps.extract_branch.outputs.branch }}/coverage/coverage](http://private.antonshell.me/github-actions/antonshell/${{ steps.extract_branch.outputs.branch }}/coverage/coverage)
repo-token: ${{ secrets.GITHUB_TOKEN }}
repo-token-user-login: 'github-actions[bot]' # The user.login for temporary GitHub tokens
allow-repeats: false # This is the default
Тестовый проект доступен на github. Также есть Pull Request с реализацией покрытия тестами. На этом пока все. Спасибо за внимание!