DEV Community

Cover image for Add test coverage badge for PHP and Pest in your GitHub repository
Roberto B.
Roberto B.

Posted on • Updated on

Add test coverage badge for PHP and Pest in your GitHub repository

If you walk through across GitHub repositories, you can see that most of them show some badges. A badge is a sort of icon that show you the status of your code, your repository, your workflow, etc.

In your Readme file in your GitHub repository, you can include your badges.
Test coverage badge

Badges are for:

  • show package version;
  • number download;
  • issues information (totals, opened, closed ...);
  • result of test executions;
  • result from GitHub Actions workflows;
  • etc...

A good website where to generate badges is https://shields.io/

If you don't find a badge that fits your need, you can create one, or you can use some tools specific for your needs.
In my last project, I needed to measure the test code coverage.

Code coverage is the percentage of code which is covered by automated tests. Code coverage measurement simply determines which lines of code / instructions have been executed through a test run, and which lines / instructions have not. The percentage is calculated based on code covered and all code (number of lines of code).

Normally, the result is shown in the terminal if your test suite is executed in a terminal, for example via command line.
You have also the option to save the result in some specific file with a "standard" format.
For example, "clover" format is an XML file that reports code coverage e some other nice metrics.
If you run the test suite in your GitHub Actions workflow, you need a specific action that is able to read clover format and use the value of coverage to render a badge.
Then a badge needs to be committed to the repository.
To recap:

  • execute test in GitHub Actions workflow;
  • save the report in clover format (clover.xml file);
  • use an "Actions" that: read the clover.xml file, produces the badge and commit/push the new badge on the repository.

In the Readme file, you need to include the badge image.

Execute test in GitHub Actions workflow

To execute tests, you can use PHPUnit or Pest. Both tools have the option for saving the report in clover format (Pest uses the feature provided by PHPUnit).

      - name: Execute tests (Unit and Feature tests) via PestPHP
        run: vendor/bin/pest --coverage-clover clover.xml
Enter fullscreen mode Exit fullscreen mode

In this way, the clover.xml file is created.

Create a badge

For creating the badge, I found this Actions: phpunit-coverage-badge.

This actions:

  • reads clover.xml file;
  • saves the badge file coverage_badge_path;
  • optionally, commits and pushes the badge via push_badge option;
  • for pushing the badge to the repo you need to set the repo_token.
      - name: Generate test coverage badge
        uses: timkrase/phpunit-coverage-badge@v1.2.0
        with:
          coverage_badge_path: 'badge-coverage.svg'
          push_badge: true
          repo_token: ${{ secrets.GITHUB_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

Now, every time you push your code on main branch, the test suite is executed and the badge is updated.

Update Readme file

Now that the badge file is created, you need to include it into your readme file with the typical markdown syntax for images:

[![Test Coverage](https://raw.githubusercontent.com/Hi-Folks/array/main/badge-coverage.svg)](https://packagist.org/packages/hi-folks/array)
Enter fullscreen mode Exit fullscreen mode

You need to replace Hi-Folks/array with your org/repo of your project.
The current badge is:
Test Coverage

The workflow file

The whole yaml file (you need to save it in .github/workflows directory):

name: Test Coverage PHP Package
on:
  push:
    branches:
      - main

jobs:
  laravel-tests:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        operating-system: [ubuntu-latest]
        php-versions: [ '8.0' ]

    name: P${{ matrix.php-versions }} - L${{ matrix.laravel }} - ${{ matrix.operating-system}}

    steps:
      - uses: actions/checkout@v2
      - name: Install PHP versions
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php-versions }}
      - name: Install Dependencies
        run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist

      - name: Show dir
        run: pwd
      - name: PHP Version
        run: php --version

      # Code quality

      - name: Execute tests (Unit and Feature tests) via PestPHP
        # Set environment
        env:
          SESSION_DRIVER: array
        run: vendor/bin/pest --coverage-clover clover.xml

      - name: Generate test coverage badge
        uses: timkrase/phpunit-coverage-badge@v1.2.0
        with:
          coverage_badge_path: 'badge-coverage.svg'
          push_badge: true
          repo_token: ${{ secrets.GITHUB_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
arielmejiadev profile image
Ariel Mejia

Hi it looks really great, thanks for the content maybe it would be nice to add in the workflow file the name and run command for phpunit/pest so we can get a pretty good idea how it looks at the end.

Another observation would be to add the file name and location for every script in the article, thanks

Collapse
 
lrljoe profile image
Joe • Edited

Significant problems with this approach!

If you have anything other than a matrix which has one value for each variable, then this action will cause significant issues as it will try to push onto a stale repo.

E.g. try running it with the following, and watch the push_badge fail miserably.

strategy:
      matrix:
        operating-system: ['ubuntu-22.04','ubuntu-20.04']
        php-versions: [ '8.0', '8.1', '8.2' ]
Enter fullscreen mode Exit fullscreen mode

To fix the issues, you can either utterly cripple the actions by setting parallel processing to 1 (thus defeating the purpose of a matrix in the first place, and causing you to wait an hour or two each time you run a significant test suite), or of course you can use an industry standard approach that doesn't involve this kind of 1st grade approach to github actions.