How to Automatically Run Your Laravel PestPHP Tests on Each GitHub Pull Request?
Bobby Iliev
Posted on September 18, 2021
Introduction
PestPHP was created by Nuno Maduro who is also one of the Laravel core team members. PestPHP is an open-source PHP Testing framework created with simplicity in mind.
PestPHP is being really actively developed and there are already plenty of learning materials online despite the fact that it is relatively new.
In this tutorial, you will learn how to use GitHub actions in order to automate your PestPHP tests and run them on each pull request.
Prerequisites
Before you start, you would need to have a Laravel application up and running.
I will be using a DigitalOcean Ubuntu Droplet for this demo. If you wish, you can use my affiliate code to get free $100 DigitalOcean credit to spin up your own servers!
If you do not have that yet, you can follow the steps from this tutorial on how to do that:
Or you could use this awesome script to do the installation:
Introductin to GitHub Actions
GitHub Actions allow you to automate your workflow. Thanks to GitHub Actions we basically have a built in CI/CD tool directly into GitHub.
If you have never used GitHub Actions, I would recommend going through this short video here:
Automatically Run your PestPHP tests
First let's start by creating the following directories in your GitHub project:
mkdir .github/workflows/
Then create a yaml file in that directory called tests.yaml
for example:
touch .github/workflows/tests.yaml
And add the following content:
name: Test Laravel Github action
on:
pull_request:
branches:
- main
- develop
jobs:
laravel-tests:
runs-on: ubuntu-latest
strategy:
matrix:
operating-system: [ubuntu-latest]
php-versions: [ '8.0','7.4' ]
dependency-stability: [ prefer-stable ]
name: P${{ matrix.php-versions }} - L${{ matrix.laravel }} - ${{ matrix.dependency-stability }} - ${{ matrix.operating-system}}
steps:
- uses: actions/checkout@v2
- name: Install PHP versions
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
- name: Get Composer Cache Directory 2
id: composer-cache
run: |
echo "::set-output name=dir::$(composer config cache-files-dir)"
- uses: actions/cache@v2
id: actions-cache
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Cache PHP dependencies
uses: actions/cache@v2
id: vendor-cache
with:
path: vendor
key: ${{ runner.OS }}-build-${{ hashFiles('**/composer.lock') }}
- name: Copy .env
run: php -r "file_exists('.env') || copy('.env.example', '.env');"
- name: Install Dependencies
if: steps.vendor-cache.outputs.cache-hit != 'true'
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
- name: Generate key
run: php artisan key:generate
- name: Directory Permissions
run: chmod -R 777 storage bootstrap/cache
- name: Run Migrations
# Set environment
env:
SESSION_DRIVER: array
DB_CONNECTION: sqlite
DB_DATABASE: ":memory:"
run: php artisan migrate
- 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
DB_CONNECTION: sqlite
DB_DATABASE: ":memory:"
run: vendor/bin/pest
With that, everytime now anyone submits a PR to your main
or develop
branches, your Pest PHP test will be automatically triggered!
The above uses SQLite, let's see how we could use MySQL instead!
Automatically Run your PestPHP tests with MySQL
In some cases, you might also want to use MySQL rather than SQLite when running your tests. This could happen in case that you have some more complex queries not using Laravel Eloquent and you are seeing incorrect results when using SQLite.
In order to do that, you could use the following configuration.
First create the following directories in your GitHub project:
mkdir .github/workflows/
Then create a yaml file called tests.yaml
for example:
touch .github/workflows/tests.yaml
And add the following content:
name: Laravel Tests
on:
pull_request:
branches:
- main
jobs:
laravel-tests:
runs-on: ubuntu-latest
# Service container Mysql mysql
services:
# Label used to access the service container
mysql:
# Docker Hub image (also with version)
image: mysql:5.7
env:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: testing
## map the "external" 33306 port with the "internal" 3306
ports:
- 33306:3306
# Set health checks to wait until mysql database has started (it takes some seconds to start)
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3
strategy:
matrix:
operating-system: [ubuntu-latest]
php-versions: [ '7.4' ]
dependency-stability: [ prefer-stable ]
name: P${{ matrix.php-versions }} - L${{ matrix.laravel }} - ${{ matrix.dependency-stability }} - ${{ matrix.operating-system}}
steps:
- uses: actions/checkout@v2
- name: Install PHP versions
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
- name: Get Composer Cache Directory 2
id: composer-cache
run: |
echo "::set-output name=dir::$(composer config cache-files-dir)"
- uses: actions/cache@v2
id: actions-cache
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Cache PHP dependencies
uses: actions/cache@v2
id: vendor-cache
with:
path: vendor
key: ${{ runner.OS }}-build-${{ hashFiles('**/composer.lock') }}
- name: Copy .env
run: php -r "file_exists('.env') || copy('.env.example', '.env');"
- name: Install Dependencies
if: steps.vendor-cache.outputs.cache-hit != 'true'
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
- name: Create storage folders
run: mkdir -p storage/framework/{sessions,views,cache}
- name: Directory Permissions
run: chmod -R 777 storage bootstrap/cache
- 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:
DB_CONNECTION: mysql
DB_DATABASE: testing
DB_PORT: 33306
DB_USER: root
DB_PASSWORD: secret
run: |
php artisan key:generate
vendor/bin/pest
The above example uses PHP 7.4 with MySQL 5.7. Make sure to adjust this so that this matches your needs.
How the action gets triggered is specified in the very beginning of the file:
name: Laravel Tests
on:
pull_request:
branches:
- main
First we specify the name, and then we specify that we want to run this action on
a pull_request
for the main
branch. Make sure to adjust the name of the branch so that it matches your setup.
Then we specify that we want to to use a MySQL container and we wait for the service to be up and running before we proceed.
If you wanted to see this in action, make sure to check out this repository here:
It includes some Pest tests along with a GitHub action that runs on each pull request towards the main
branch.
GitHub Actions configurator for your Laravel Application
If you are getting overwhelmed looking at the GitHub actions yaml files, do not worry, there is an amazing open-source tool created by Roberto B that let's you generate your GitHub Actions yaml for your Laravel Application automatically based on your exact needs:
You can find the tool here:
GitHub Actions configurator for your Laravel Application
You can use the UI to select the features that you need and it will automatically built up the YAML file for you!
Make sure to support Roberto B by following him on Twitter!
Conclusion
If you want to learn more about PestPHP, I would recommend going through this crash course here:
Introducing Pest - An elegant PHP testing framework
If you like PestPHP make sure to star it on GitHub:
Posted on September 18, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
September 18, 2021