Introducing the WP testing project – WordPress testing refactored

During development of other projects I got annoyed with the process for setting up the standard WordPress testing setup with PHPUnit. It was limiting and combining unit and integration(acceptance etc) testsuites for local development meant running tests became very slow. This is because the default setup installs and loads WordPress each run. This drawback could be handled by having different PHPUnit config files but I thought there must be a way around this.


So I took it upon myself to refactor and restructure the WordPress testing tools into a separate project. It is now Composer compatible with autoloading support. It is not a drop in replacement for the current WordPress testing setup, but it is easy to make an old project compatible.

The project code is available on GitHub in this repo WP Testing.

What can you do with the new WP testing framework?

The framework supports separate test suites with separate bootstrap files. By default it supports unit, integration, functional and acceptance test suits with corresponding bootstrap files.

It's also possible to make separate plugin/theme setups so you can test compatibility with various WP site setups. This is done by creating a separate testsuite per setup. If you want to add a non standard test suite you need to implement your own TestListener. This is the PHPUnit class that I have used to enable separate bootstrap files per testsuite. It's very easy to make your own implementation of the TestListener. Future versions of “WP Testing” will handle custom test suites by default.

Getting started

Easiest way to get going is to install the framework via Composer so you need to add the framework as a dependency in your Composer file.
The –dev tag tells Composer that this dependency is only required during dev installs.

1

composer require --dev "ArtOfWP/wp-testing"

Your first PHPUnit config and bootstrap

You can find an example conf file in the GitHub repo, phpunit.example.conf
Below I’ll deconstruct the conf file.

1

2

<phpunit bootstrap="tests/bootstrap.php"

[...]>

Bootstrap attribute points PHPUnit to the file it should load first. This file is usually where you add your WordPress test setup code. The code example below assumes you have the bootstrap file in for example: projectdir/tests. Composer vendor folder is usually a subdirectory to projectdir.

Bootstrap

In WP Testing all you need to add to the main bootstrap file is:

1

2

<?php

require dirname(__DIR__) . '/vender/autoloader.php';

You need to add this to the main bootstrap file due to how PHPUnit works. It looks at what tests you have defined and loads all test files to memory before running the tests.

Testsuites

1

2

3

4

5

<testsuites>

    <testsuite name="unit">

        <directory suffix="Test.php">./tests/unit</directory>

    </testsuite>

</testsuite>

The above is how to add a testsuite to your PHPUnit setup. The default testsuite names that are supported are unit, integration, functional and acceptance.

Bootstrap loading

For the various bootstrap to be loaded per testsuite you need to add a PHPUnit listener to the config file. BootstrapLoader is a very simple implementation of a Listener.

1

2

3

4

5

    <listeners>

        <listener class="\ArtOfWP\WP\Testing\BootstrapLoader">

        </listener>

    </listeners>

</phpunit>

If you want to add other testsuite or make any other changes making your own bootstrap loader is very simple. Below is the code for the default bootstrap loader implementation.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

class BootstrapLoader extends \PHPUnit_Framework_BaseTestListener

    /**

     * @param \PHPUnit_Framework_TestSuite $suite

     */

    public function startTestSuite(\PHPUnit_Framework_TestSuite $suite)

        switch($suite->getName())

            case "unit":

            case "integration":

            case "acceptance":

            case "functional":

                echo "\nRunning $suite->getName() tests\n";

                if(file_exists(getcwd()."/tests/$suite->getName()/bootstrap.php"))

                    require getcwd()."/tests/$suite->getName()/bootstrap.php";

                else if(file_exists(getcwd()."/tests/bootstrap-$suite->getName().php"))

                    require getcwd()."/tests/bootstrap-$suite->getName().php";

        

    

 

Your First Test cases

Unit tests

For unit tests just write your tests as you normally would if you are not working with WordPrese, use the standard PHPUnit test case. Any classes that need to be loaded you can include in the bootstrap file. Name should be bootstrap-unit.php if it's in the root tests folder or bootstrap.php if you put it in the tests/unit folder.

1

2

3

4

5

<?php

// Include class files according to your plugin

// or theme file structure.

require_once dirname(__DIR__) . '/load-my-plugin-classes.php';

//require_once dirname(__DIR__) . '/my-autoloader.php';

For testing purposes its better to not include all your classes in your main plugin file. If you include your main plugin file in the unit test bootstrap file you will most likely get lots of function undefined errors and so forth.

1

2

3

4

5

6

7

8

9

namespace tests\unit\Some\Plugin;

class MyClass extends \PHPUnit_Framework_TestCase

    public function setUp()

    

    public function testMethod()

    

    public function tearDown()

    

 

Integration/Functional tests

Integration tests require a bit more elaborate bootstrap since we need to tell WordPress which plugins/theme to load and also start the installation process and make WordPress ready for testing.

1

2

3

4

5

6

7

8

<?php

use ArtOfWP\WP\Testing\WP_Bootstrap;

$GLOBALS['wp_tests_options'] = array(

    'active_plugins' => array(

        'my-plugin/my-plugin',

    ),

);

(new WP_Bootstrap())->run();

Configuring the $GLOBALS variable is the same way that you configure standard WordPress test setups. What's new is that thanks to autoloading you don’t have to include the bootstrap file yourself, I have made it a proper class. Everything related to the WordPress Core test suite has been removed as well, such as integration with trac.

If you want to make a test case that runs against WordPress you extend from WP_UnitTestCase as you do currently. The difference is that since the test framework now uses namespaces you need it to write the use statement as well. This is usually handled by your IDE so that's not something you have to give much thought to.

1

2

3

4

5

6

7

8

9

10

11

12

13

<?php

namespace tests\functional\Some\Plugin;

use ArtOfWP\WP\Testing\WP_UnitTestCase;

class UserMessagesServiceTest extends WP_UnitTestCase

    public function setUp()

        parent::setUp();

    

    public function testMethod()

    

    public function tearDown()

        parent::tearDown();

    

 

How do I run my test suites?

If you just call standard phpunit then all test suites will be run. To run only one testsuite you write phpunit --testsuite=name where name is the name of the testsuite.

What's next?

I think there can be more improvements in how test setups are made when you configure integration tests. I also want to remove the rest of the dependencies on the default WordPress test framework.


If you have any ideas or questions just comment below.