Basics of Writing PHPUnit tests


Our phpunit.xml file will, by default point to the /tests directory and php files with the test-prefix will be loaded. Inside each of these files we’ll define a class that tests a specific aspectTypically either a class or a file/module of our custom code.

WPUnit Test Case

Our Test classes will extend the WP_UnitTestCase which extends the PHPUnit\Framework\TestCase and provides some helpful factory methods for WordPress

setUp and tearDown methods, while not required are very helpful fixtures that run before and aftersetUp before, and tearDown after. You will typically have more setup than teardown. each of our tests.


class WSRTPTestLogging extends WP_UnitTestCase{

function setUp(){


function tearDown(){


function testCreateLogEntry(){


The tests themselves will occur inside methods that are prefixed with test_. You can write methodsthis is just code after all that don’t start with test_ but you’ll need to call those from other methods from them to be included as part of the test battery.

Example: Test Method

function test_basic()
    $this->assertGreaterThan(0, $this->product);
    $this->assertGreaterThan(0, $this->reg_coupon);
    $this->assertGreaterThan(0, $this->subscription);

    $this->assertEquals('WSRTP_Tier', get_class($this->tier));
    $this->assertEquals('WSRTP_Rule', get_class($this->rule));

    $product=new WC_Product_Subscription($this->product);
    $this->assertEquals(100, $product->get_price());

Within our code, our goal is to check assumptions about our code using assertions. So we run some code, get some outputs, and test our assertion about what those output should be. There are a wide array of assertions we can make, but a good starter set is

function test_get_global_plan(){
    $this->assertEquals('WSRTP_Plan', get_class($plan));
    $this->assertEquals('global', $plan->get_context());
    $this->assertEquals(0, $plan->get_context_id());
    $this->assertEquals('global', $tier->get_context());
    $this->assertEquals(0, $tier->get_context_id());

Frequently, with integration testing, it can be helpful to write basic tests that use the API of external software (e.g. WooCommerce) that our software depends on to function correctly. Then, when an update is pushed out, our tests will run some quick sanity checksThis can help quickly pinpoint where an update has changed and where, specifically, it’s breaking your code. for continued compatibility

Running tests

As we write tests, we’ll frequently run phpunit in the docker container. This will run through all of our tests, and give us a happy green “All clear” if everything checks out. Or descriptive error messages if our code throws an error, or one of our assertions fails.


Where the WP_UnitTestCase class really helps us, is by providing a series of factories that can quickly createtakes the same arg as the create_ methods some of the core WordPress data objects to use in the tests.

Object Code Notes
Post $this->factory()
Useful for all manner of post_types
Attachment $this->factory()
When your tests involve interactions with media
Comment $this->factory()
User $this->factory()
Trying to run a test as admin? You’ll need to create an admin user and set them as current user
Term $this->factory()
Useful for all manner of taxonomies, just be sure the taxonomy is registered as part of your bootstrap process, or inside your test fixtures
Category $this->factory()
Tag $this->factory()

Additional Considerations & Conclusion

Test Artifacts

As you run your tests, it is likely that you’ll create changes to the test WordPress database creating entries for your tests to test against—that’s fine. What’s not fine, is letting those persist between testsOur use of Docker will help us out here, as it won’t maintain persistent data between sessions. Ensure your bootstrap.php clears out old data before starting a new test run.

Opportunities to Refactor

As you start testing, you’re bound to find you’ve got some chunks of code that are impossible to test. GenerallyTemplates and methods that output html are a reasonable exception, writing tests for that is usually dumb., testable code is good code, consider untestable code to be a good opportunity to refactor to something better.

We’ve barely scratched the surface, but hopefully that little taste is enough to whet your appetite. Up next, we’ll talk about ways to handle particularly challenging test cases/


Keyboard shortcuts

CTRL+Shift+F Search slideshow
F Fullscreen view
CTRL+Click Zoom in
Esc Topic overview
Right arrow,
Down arrow
Next slide
Left arrow,
Up arrow
Previous slide

Color codes

Hover over text more additional info
Link to an external resource
Link to an internal slide
If buttons aren't working, click in the screen to "focus" your browser