Getting started with PHP tests
Local Development
If Starting from scratch
- Download a zip from the
cno-starter-themeor start a new Github repo with that as the template. - Migrate all files to a fresh Local WP site (including the
.gitfolder if it exists) - Follow the readme to get the theme started.
If starting on an existing repo
- Create a
binfolder inside the theme folder and add 2 files:install-wp-tests.shandlocal-mysql-socket.sh - Copy the contents from the Github Template Theme repo
- Update
composer.jsonto include the following key/value pairs:autoload-devscripts.testandscripts.install-tests- Update the path to be your theme name (from
cno-starter-themetoyour-theme-name) require-dev: add the missing packages (phpunit&yoast/phpunit-polyfills
- Run
composer update -wto update/install new dependencies - Add
.wp-teststo your.gitignore
# .gitignore
# ...rest of .gitignore...
# Tests
.wp-tests/Enabling Code Coverage
- In Local, click on
Site Folder, then navigate toconf/php/php.ini.hbs. - Open the file with TextEditor (VS Code autoformat can royally screw things up) and find the following:
# conf/php/php.ini.hbs
{{#if xdebugEnabled}}
xdebug.mode=debug,develop- Add ‘coverage’ as the third item in the list
# conf/php/php.ini.hbs
{{#if xdebugEnabled}}
xdebug.mode=debug,develop,coverage- Add the resulting new files to `.gitignore
# .gitignore
# ...rest of .gitignore...
# Tests
.wp-tests/
.phpunit.result.cache
.phpunit.cache
html-coverage/Init Test Suite Locally
- Click the
Site Shellbutton on a local WP site - Run
wp scaffold theme-tests [theme-name]- When you see
Warning: file already exists, skip the file - Delete / move the
.circle-cifolder,.phpcs.xml.distfile, andphpunit.xml.dist(if you need thephpunitxml, copy it from the template repo and place it in the root of the repo (/public). Be sure to update the theme name if doing so!
- When you see
- Run
composer install-tests - Run
composer test
Integration Tests with ACF
Install the Test-Aware ACF (Pro) Plugin
If your tests require ACF fields (e.g. get_field), you’ll need to add some extra configuration to your composer.json and bootstrap files
- Choose either ACF or ACF Pro to install (go with ACF unless you need specific Pro functions)
- Add the following to your
composer.json:
{
// ...rest of json...
"extra": {
"installer-paths": {
"vendor/{$name}/": [
"wpengine/advanced-custom-fields"
]
}
},
"repositories": [
{
"type":"composer",
"url":"https://composer.advancedcustomfields.com"
}
],
"require-dev": {
// ...other required packages...
"wpengine/advanced-custom-fields": "*"
}
}- Run
composer update -w - Update your
theme/tests/bootstrap.phpfile with the following function:
tests_add_filter( 'muplugins_loaded', '_manually_load_acf' );
/**
* Manually load the ACF plugin for testing.
*/
function _manually_load_acf() {
if ( ! defined( 'WP_PLUGIN_DIR' ) ) {
define( 'WP_PLUGIN_DIR', dirname( $_tests_dir, 1 ) . '/wordpress/wp-content/plugins' );
}
// Add ACF
$acf_path = dirname( __DIR__, 4 ) . '/vendor/advanced-custom-fields';
// turn off the ACF admin UI to speed tests and reduce noise
if ( ! defined( 'ACF_LITE' ) ) {
define( 'ACF_LITE', true );
}
if ( file_exists( $acf_path . '/acf.php' ) ) {
require_once $acf_path . '/acf.php';
} elseif ( file_exists( WP_PLUGIN_DIR . '/advanced-custom-fields/acf.php' ) ) {
require_once WP_PLUGIN_DIR . '/advanced-custom-fields/acf.php';
} else {
// Optional: throw or log so CI fails loudly
fwrite( STDERR, "ACF plugin not found at {$acf_path}/acf.php or " . WP_PLUGIN_DIR . "/advanced-custom-fields/acf.php\n" );
}
}Set up ACF within your test
According to ChatGPT, best practice is to create an isolated field group for what you’re testing. So, here’s an example for event post type fields
- in
Class::set_up_before_class, callacf_add_local_field_groupand register the fields you need for testing - In
Class::tear_down_after_class, callacf_remove_local_field_groupand then callparent::tear_down_after_class()
You could also call this in set_up() and tear_down() depending on your test needs
Weirdness
- PHPUnit must run version
^9until things get updated (which you can track here)—even though PHPUnit is on v12 (at time of writing). - The final lines of
install-wp-tests.shsymlink the WordPress tests directory so PHP intelephense knows about the test classes (no more red squigglies). You should see a.wp-tests/wordpress-tests-libfolder with/data,/includes, awp-tests-config.phpfile and awp-tests-config.php.bakfile.- If you see these and see red squigglies, reload the window (VS Code Command Palette (
Cmd + Shift + P) then"Developer: Reload Window")
- If you see these and see red squigglies, reload the window (VS Code Command Palette (
Further Reading
- WordPress docs on Writing PHP Tests
- WP_UnitTestCase_Base code
- Udemy Course on PHPUnit
- PHPUnit Docs