Running PHPUnit on GitHub Actions
A little back story. Last year GitLab announced changes on their free tier user limits. This somehow impacted our team since we relied on their generous offer on unlimited private repositories for organization. We have been on GitLab for almost half decade. But now we’re given 2 options: migrate to self-hosted GitLab or move to their premium plan for around $19/developer/month (now it’s $29).
So we went for third option: migrate to GitHub 🎉
It was for obvious reason. GitHub is 7x cheaper for $4/developer/month and we got all we need at the time: unlimited private repositories for organization. Other interesting feature was Actions, since we can setup workflows easily.
I once setup GitLab Pipelines several years ago and found it was a bit complicated (I don’t know how it differs now). As far as I remembered, I need to build my own image and define my workflows manually from scratch. With GitHub Actions, we can easily looking for ready-to-use workflow from their Marketplace, place some yaml configurations, and done. We can also combine them or if we can’t find any, we can always build our own.
Experimenting with Our Test Suites
Currently, we doesn’t have continuous delivery setup for dicoding.com, so engineers still deploy their feature manually. So we tried to utilize Actions to run our test suites instead. We have range of tests: unit, integration, component, E2E, and static analysis. For starter, we think unit tests and static analysis are good enough since they should be the easiest to setup.
First, we define when the workflow should run. We decided to run them when something changes in a PR. For this experiment, our goal is:
To make sure every PR submitted is passing the unit tests and static analysis, thus prevents merging issues/bugs to main branch.
For your information, we’re using PHPunit for unit tests and Psalm as static analysis tool. They are great tools for our PHP stack. Then we start looking ready-to-use workflow for those 2 tools and found 2 interesting actions:
We ended up using both actions for now and here is our existing workflow configuration:
name: Pull Request Check
on: [pull_request]
jobs:
unit-test:
name: Unit testing
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Cache Composer dependencies
uses: actions/cache@v3
with:
path: /tmp/composer-cache
key: ${{ runner.os }}-${{ hashFiles('composer.lock') }}
- name: Installing dependencies
uses: php-actions/composer@v6
with:
php_version: 8.1
php_extensions: "json zip sodium pcntl bcmath"
- name: Running unit test
uses: php-actions/phpunit@v3
with:
version: 9.6
php_version: 8.1
php_extensions: "json zip sodium pcntl bcmath"
args: "-d date.timezone=Asia/Jakarta"
memory_limit: 300M
configuration: phpunit.xml
testsuite: unittest
psalm-test:
name: Checking psalm
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, bcmath, intl, gd, exif, iconv, imagick, json, lz4-kjdev/php-ext-lz4@0.4.3
coverage: none
- name: Cache composer dependencies
uses: actions/cache@v3
with:
path: vendor
key: composer-${{ hashFiles('composer.lock') }}
- name: Run composer install
run: composer install -n --prefer-dist
- name: Run psalm
run: ./vendor/bin/psalm.phar --output-format=github
I personally think shivammathur/setup-php is better choice, since it’s very general, configurable, and can support almost all of your need of running PHP scripts in Actions.
So, What’s Next?
I tried to run our integration tests and failed instantly 😆
But it was expected as we need setup additional services, like database and cache. In the future we might run all of our test suites in Actions and who knows, maybe we’ll setup CI/CD pipeline? Let’s see where it goes.