3

Pretty much what the title says.

I have a custom plugin written, that relies on the use of admin-ajax to handle various forms and actions. That's all working fine, however as the various functions echo out responses I have to throw in a die() after the echo function. ie:

echo $return_string;
die();

All fine, however this unfortunately breaks my PHPUnit tests as throwing in a die() will kill the script and prevent the unit test from working. Without the die I receive the traditional 0 at the end of my response, which isn't what I want. Have also tried the WP recommended:

wp_die();

Does anyone have any ideas on how to get around this?

1
  • If it is a unit test, you have to mock wp_die() anyway. Then write a mock that doesn't call die().
    – fuxia
    Commented Apr 18, 2017 at 18:55

2 Answers 2

8

If you use wp_die() you can utilize the tools included with WordPress's PHPUnit test suite. The WP_Ajax_UnitTestCase provides the _handleAjax() method that will hook into the actions called by wp_die() and throw an exception, which will prevent die() from being called. I've written a tutorial on how to use WP_Ajax_UnitTestCase, which explains all of the features it provides, but here is a basic example:

class My_Ajax_Test extends WP_Ajax_UnitTestCase {

    public function test_some_option_is_saved() {

        // Fulfill requirements of the callback here...
        $_POST['_wpnonce'] = wp_create_nonce( 'my_nonce' );
        $_POST['option_value'] = 'yes';

        try {
            $this->_handleAjax( 'my_ajax_action' );
        } catch ( WPAjaxDieStopException $e ) {
            // We expected this, do nothing.
        }

        // Check that the exception was thrown.
        $this->assertTrue( isset( $e ) );

        // Check that the callback did whatever it is expected to do...
        $this->assertEquals( 'yes', get_option( 'some_option' ) );
    }
}

Note that technically speaking, this is integration testing rather than unit testing, as it tests a complete cross-section of the callback's functionality, not just a single unit. This is how WordPress does it, but depending on the complexity of your callback's code, you may also want to create true unit tests for it as well, probably abstracting portions of it out into other functions that you can mock.

3
  • 1
    just a comment, in the end, it also depends on what do you want to do, a unit test, or integration test. for a unit test you might want to make sure you hooked the right hook, and that you generate the right output per input, but when you do it together like here (and probably what core does), you lose the ability to pinpoint the root cause of the failure. Commented Apr 18, 2017 at 20:34
  • 1
    @MarkKaplun That's true, and I was going to mention that WordPress uses more integration-style tests rather than pure unit tests. I assumed though that OP was probably doing things integration style already, if they had this question. (Edit: I've updated the answer.)
    – J.D.
    Commented Apr 19, 2017 at 0:25
  • I'm going to take a look at that tutorial this morning as there are still some tests I need to tie together.
    – rich
    Commented Apr 19, 2017 at 9:42
3

Unfortunately, the ajax hook handler has to die otherwise wordpress will continue running and some more output might be generated (or might not, but you don't want to rely on it).

The solution is probably to isolate your response generation code in a function and test the output it generate, and then on the hook handler itself just do

echo echo_fn(....);
wp_die()

Then in your unit tests you test only echo_fn().

1
  • This is what I ended up doing for the simplicity, horribly annoying to say the least!
    – rich
    Commented Apr 19, 2017 at 9:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.