WordPress Unit Testing with PHPUnit and WP_UnitTestCase

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.