Unit testing in WordPress

TL; DR

Unit tests are code that tests that your functions return what you intended. You benefit more from this the more complex your project is.

What are unit tests?

Maybe you’ve already heard of unit tests, or even used them yourself? You haven’t? You should start doing so!

Unit tests are code that tests code. Specifically, that the methods you have written return the result you intended. It’s especially useful in more complex projects where one class can be used by several other classes, and the more general the class, the more well-tested it needs to be.

Unit testing in WordPress

In WordPress, testing is a bit special. For one thing, the flow is a bit different in WordPress compared to many frameworks. In WordPress, as in Drupal and some other systems, hooks and filters are used, for example, which means that it can be difficult to trace the flows in the code. On the other hand, it is difficult to test the view part, such as themes and visual functions. In many frameworks there is support for testing views as well, but in WordPress we have to rely on Selenium tests and the like. There is simply quite a lot of code that is not unit testable.

Tools

However, WordPress has a good support for unit tests. On the one hand, there are unit tests for all core functions, and on the other hand, there are tools for easily setting up skeleton tests for your own projects using WP-CLI. We also use some additional tools that help us with our testing work.

  • Travis CI – Continuous Integration means that you continuously build your system and run the tests you have to detect problems. The frequency can be different, but often it is part of the flow when you commit your code. For public projects on github, Travis is free to use. You can also set up a matrix of browsers, WordPress version and Php version that you want to test.
  • Scrutinizer – This tool helps to increase code quality by looking for possible bugs and suggestions for code improvements.
  • CodeSniffer – In CodeSniffer you can set up rules for your code standard, e.g. whether variables should use CamelCase, or whether code blocks should start on the same line as the previous or new line. The program then helps you to detect if you are breaking these rules and can also help to fix some of the problems.

Like almost all php projects, WordPress uses the PHPUnit library. When you write your test, you create an object of the class you want to test. You pass in various parameters and then compare the result you get back with the result you expect. There is a large set of comparison methods, such as assertTrue, assertEquals, assertException, etc.

What you should and should not test

So what should you test? There are a few things that might be appropriate to test.

  • Correct values – Pass in values you expect the method to receive and compare with what it should return. If you have a method that receives a string, then pass in a string and make sure you get back the correct result.
  • Extreme values – What happens if you pass floating point numbers to a method that expects integers? What happens if you pass an empty string into a method?
  • Error handling – Check what happens if you use the method in a way it is not built for, for example if you pass in parameters with the wrong format (e.g. string instead of number) or maybe the wrong number of parameters.

In WordPress there are some specific things you can test.

  • Are my Custom Post Types set up correctly and can I create new items with them?
  • Are the plugin’s roles created and do they have the correct rights?

So there is a big responsibility on you to write appropriate tests, but just like with any programming, there is always the possibility to go back and improve your tests. In fact, it is a good way to work with bugs. When you discover an undesirable behavior, you write a new test that handles it.

Things that are less suitable for testing are things that WordPress tests itself. For example, there is no point in testing that WordPress core functions do what they should because all stable WordPress versions are built with the tests that exist.

Fixtures

One thing that can be interesting to know about is fixtures. If your method uses its own data structures, you often want to be able to control the result. Fixtures are a way to control data by setting up ready-made data objects. This way you can always know that your data contains what you think it should. For example, if you want to check that your method that retrieves all bookings between April 5-10, you can use a fixed set of data to check that your method works properly. It’s worth noting that the support for fixtures in WordPress isn’t very well developed, at least not yet.

Visibility

One problem with testing methods is about visibility. Since you create an object of the class you’re testing, you can’t access the class’s private methods. There are slightly different philosophies on how to handle these. Many people think that you shouldn’t test private methods, but if you need to, there is a solution called ReflectionClass. Using it, you create an object of your class and simply temporarily change its visibility.

Kodblock

Examples

To start with tests, you can use WP-CLI to set up a test skeleton.

wp scaffold plugin-tests coolstrings

This is what the created folder structure might look like:

Mappvy

In our plugin we have created two methods, one to generate strings and one to remove unwanted characters from it:

public function generateCoolString( $length = 20 ) {
    $seed = 'abcdefghijklmnopqrstuvwxyz'
            . 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
            . '0123456789!@#$%^&*()';
 
    $rand = '';
    $len = strlen( $seed ) - 1;
    for ( $i = 0; $i 

Our tests, located in tests/test-cool-string.php, look like this:

public function test_generate_cool_string() {
    $cool_object = new CoolString();
 
    // Test some good values
    $test_values = [
        20,
        30,
        100
    ];
 
    foreach ( $test_values as $value ) {
        $cool_string = $cool_object->generateCoolString( $value );
 
        $this->assertTrue( is_string( $cool_string ) );
        $this->assertEquals( strlen( $cool_string ), $value );
    }
 
    // Test some bad values
    $test_values = [
        -5,
        'kalle',
        null,
        false
    ];
 
    foreach ( $test_values as $value ) {
        $cool_string = $cool_object->generateCoolString( $value );
 
        $this->assertFalse( $cool_string );
    }
}
 
public function test_sanitize_cool_string() {
    $cool_object = new CoolString();
 
    // Test some good values
    $test_values = [
        v4A#Pa1OSzuJ&8q0Tr$^' => 'AaOu',
        'eEVLmrQuxjl$q0MGzwNs' => 'eEu',
        'wUZckBvr0T4xJMYo*POH' => 'UoO'
    ];
 
    foreach ( $test_values as $key => $value ) {
        $cool_string_sanitized = $cool_object->sanitizeCoolString( $key );
 
        $this->assertTrue( is_string( $cool_string_sanitized ) );
        $this->assertEquals( $cool_string_sanitized, $value );
    }
}

Run the tests by navigating to the plugin folder and running phpunit.

Console Fail

Using our tests, we can see that we have made some errors in the code.

  • We have hardcoded how long the string we return should be.
  • We have accidentally forgotten that o/O should be authorized letters.
  • We are not handling incorrect parameters.

With a few changes to our code, the tests go through:

public function generateCoolString( $length = 20 ) {
    if ( !is_numeric( $length ) || $length 

Now our tests are going through!

Console OK

TDD

Finally, a few words about Test Driven Development, or TDD. TDD is a way of developing based on writing your tests first, then coding and refactoring until the tests go through and repeat in a circle.

Some detractors think that TDD takes too long to use, because you also have to spend time writing tests and not just implementing features, while proponents believe that you quickly save that time in fewer bugs.

WordPress is only partially suitable for TDD because a significant part of the code it produces cannot be tested.

Loading