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.
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.
<?php
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.
<?php
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
assertTrueand
assertEquals
<?php
function test_get_global_plan(){
$plan=WSRTP_Plan::get_global_plan();
$this->assertEquals('WSRTP_Plan', get_class($plan));
$this->assertEquals('global', $plan->get_context());
$this->assertEquals(0, $plan->get_context_id());
$tier=$plan->add_tier();
$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
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() ->post ->create($args) |
Useful for all manner of post_types |
Attachment | $this->factory() ->attachment ->create($args) |
When your tests involve interactions with media |
Comment | $this->factory() ->comment ->create($args) |
|
User | $this->factory() ->user->create($args) |
Trying to run a test as admin? You’ll need to create an admin user and set them as current user |
Term | $this->factory() ->term ->create($args) |
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() ->term ->create($args) |
|
Tag | $this->factory() ->tag ->create($args) |
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.
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/