Testing WordPress plugin is sometimes tricky. There are a lot of practices that don’t make sense nowadays, but have their roots in older versions of PHP. WP development team tries to think up workarounds to make it possible to test those cases that seem untestable on the first glance.

I know at least two cases that you might come across while writing another test.

Die

For example, how can you test a call to die()? It sounds impossible as it just breaks the normal program flow. And this is why you should never use it in you WordPress plugin. You must use wp_die() instead.

In the abstract test case that is shipped with WordPress, the handler is specified which throws an exception instead of actually dying. And that’s really handy for us.

<?php

class Die_Test extends \WP_UnitTestCase {
    public function testWpDie_WhenCalled_ThrowsException() {
        $this->expectException( WPDieException::class );
        $this->expectExceptionMessage( 'foo' );
        wp_die( 'foo' );
    }
}

Redirect

Another case I struggled earlier was the redirection. Mostly, because it also calls die or exit afterwards.

First of all, use wp_redirect() for that purpose. Secondly, there are a few approaches to solve the problem.

The “simplest” is to define your own wp_redirect function before it was loaded from WordPress.

Another popular solution is to utilize standard PHP error handlers.

I decided to go with a solution which similar to how it works for wp_die. We just specify a “filter” that throws an exception.

<?php

class Redirect_Test extends \WP_UnitTestCase {
    public function set_up()
    {
        parent::set_up();
        add_filter( 'wp_redirect', [ $this, 'filterWpRedirect' ], 10, 2 );
    }

    public function tear_down()
    {
        parent::tear_down();
        remove_filter( 'wp_redirect', [ $this, 'filterWpRedirect' ], 10 );
    }

    public function filterWpRedirect( $location, $status ) {
        throw new WPDieException( $location, $status );
    }

    public function testWpRedirect_WhenCalled_ThrowsException() {
        $this->expectException( WPDieException::class );
        $this->expectExceptionMessage( '/foo' );
        $this->expectExceptionCode( 302 );
        wp_redirect( '/foo', 302 );
    }
}

This solution looks as powerful as simpler for me. Therefore, I consider is as the best solution for this purpose.

Conclusion

Writing tests might be challenging and tricky. Fortunately, we’re not the first ones on this journey, and hopefully smart people from dev team already solved most puzzles we encounter.

However, that doesn’t mean we can just ignore good architecture and testability. Pay attention to code structure and good practices, write tests and ship a product of a high quality.

Categorized in: