For the complete documentation index, see llms.txt. This page is also available as Markdown.

🧪Testing

PHPUnit unit tests for PressGang's own PHP framework code — no WordPress install required — plus where to go for full theme end-to-end testing.

PressGang ships with a unit test suite so you can verify framework behaviour and safely refactor without a running WordPress installation.

🧰 Stack

  • PHPUnit 9.6 — test runner

  • yoast/wp-test-utils ^1.2 — provides BrainMonkey integration and pre-stubbed WordPress functions (matches Timber 2's own test stack)

  • BrainMonkey — mocks WordPress functions (add_action, apply_filters, wp_cache_get, etc.) in pure PHP

No WordPress database, no web server, no Docker required.

▶️ Running Tests

Terminal
composer test            # alias for test:unit
composer test:unit       # run the full unit suite
vendor/bin/phpunit --filter ConfigTest           # run a single test class
vendor/bin/phpunit --filter loads_and_caches     # run a single test by name
vendor/bin/phpunit --list-tests                  # list all discovered tests

🗂️ Directory Structure

Tests mirror the src/ layout under tests/Unit/:

tests/
tests/
├── bootstrap.php              # autoloader + THEMENAME/ABSPATH constants
└── Unit/
    ├── TestCase.php           # base class (extends YoastTestCase)
    ├── Blocks/                # BlockClassManager
    ├── Bootstrap/             # Config, FileConfigLoader, Loader
    ├── Configuration/         # Sidebars, Menus, CustomPostTypes, Actions
    ├── ContextManagers/       # Menu, Site, ThemeMods, AcfOptions, WooCommerce
    └── ServiceProviders/      # TimberServiceProvider

✍️ Writing a New Test

1

Create the test class

Place it under tests/Unit/ mirroring the src/ path. For example, a test for src/Configuration/Sidebars.php goes in tests/Unit/Configuration/SidebarsTest.php.

2

Extend the base TestCase

The base TestCase extends Yoast\WPTestUtils\BrainMonkey\YoastTestCase, which handles BrainMonkey setup and teardown automatically. It also provides:

  • resetSingletonInstances() — clears ConfigurationSingleton state between tests

  • setPostData() / clearPostData() — helpers for testing form validators

3

Mock WordPress functions with BrainMonkey

4

Reset singletons when needed

Any test that touches a ConfigurationSingleton subclass should reset state:

🔧 Testing Context Managers

Context managers depend on static calls (Timber::get_menu(), new Site()) and global helpers (config()) that cannot be mocked directly with BrainMonkey. PressGang uses the protected method pattern — static calls are wrapped in protected methods that tests override via anonymous subclasses:

This avoids @runTestsInSeparateProcesses (which is 5-10x slower) and keeps tests fast and deterministic.

💡 Tips and Gotchas

BrainMonkey apply_filters signature

Pre-loaded functions cannot be mocked

Functions loaded via Composer's files autoload (like the config() helper) are defined before BrainMonkey initialises. Extract calls to these functions into protected methods and override them in tests.

wp_parse_args is pre-stubbed

YoastTestCase pre-stubs wp_parse_args to behave like array_merge($defaults, $args) — no need to mock it yourself.

🚢 End-to-end testing

Unit tests cover the framework's PHP in isolation. For testing an actual theme — every route rendered in a real browser, accessibility, visual regression, derived fixtures — see Shakedown, the fleet's e2e harness. It needs zero authored tests to start: the suite is derived from your theme's config.

Last updated