Unit tests help you catch regressions early and refactor with confidence. WordPress provides a testing framework built on top of PHPUnit — WP_UnitTestCase — that gives you a fresh database for each test run, factory methods for creating posts and users, and assertions specific to WordPress.
Problem: How do you write automated tests for WordPress plugins and themes to catch regressions before they reach production?
Solution: Use PHPUnit with the WordPress test suite bootstrapped by wp scaffold plugin-tests. Extend WP_UnitTestCase for WordPress-aware tests that run against a temporary database and reset state between tests.
Set up the test scaffold for a plugin using WP-CLI:
# Generate the test scaffold
wp scaffold plugin-tests my-plugin
# Install the WordPress test suite (replace DB details)
bash bin/install-wp-tests.sh wordpress_test root '' 127.0.0.1 latest
# Run tests
./vendor/bin/phpunit
A typical test class for a plugin function:
<?php
class Test_My_Plugin extends WP_UnitTestCase {
public function setUp(): void {
parent::setUp();
// Register the CPT / taxonomy / hook so every test starts clean
my_plugin_init();
}
/** Test that a post with the correct meta is returned */
public function test_get_featured_posts_returns_correct_count() {
// Create 5 posts, mark 3 as featured
$featured_ids = $this->factory->post->create_many( 3 );
foreach ( $featured_ids as $id ) {
update_post_meta( $id, '_is_featured', '1' );
}
$this->factory->post->create_many( 2 ); // non-featured
$result = my_plugin_get_featured_posts();
$this->assertCount( 3, $result );
}
/** Test sanitisation */
public function test_sanitise_option_strips_tags() {
$dirty = '<script>alert("xss")</script>Hello';
$clean = my_plugin_sanitise_option( $dirty );
$this->assertEquals( 'Hello', $clean );
}
/** Test a filter is applied */
public function test_filter_modifies_title() {
$post_id = $this->factory->post->create( [ 'post_title' => 'Original' ] );
add_filter( 'the_title', function( $title ) {
return 'Prefix: ' . $title;
} );
$this->assertEquals( 'Prefix: Original', get_the_title( $post_id ) );
}
}
NOTE: The WordPress test suite runs against a real database (configured in wp-tests-config.php) and rolls back every transaction after each test. Avoid hardcoding database credentials in version-controlled files — use environment variables instead, and add wp-tests-config.php to .gitignore.