3

The constructor in my class adds an action to the 'init' action hook:

class My_Custom_Post_Type {

    function __construct( $type ) {
        $this->type = $type;
        add_action( 'init', array( $this, 'register_my_type' );
    }

    function register_my_type() {
        register_post_type( $this->type);
    } 
}    

I was trying to test this in a unit test and finally realized that there was no reason for the 'init' action hook to fire. Is there any way to test that the register_my_type method is being called and that a new post type is being registered?

Edit:

The main source of my confusion came from not understanding the relationship between phpunit, the WordPress test suite, my class code, and my test code.

What I now understand is that with the WordPress developer tools installed in the way the is suggested by this tutorial or through WP-CLI, a call to phpunit loads a bootstrap file which then hooks the plugin into the muplugins_loaded action hook. The bootstrap file then loads the WordPress test environment. After WordPress has finished loading the init hook is run. Plugin code that makes use of init should work as expected.

Tests are mostly just normal code that is making use of available functions or classes. What is different about them is that they are written as methods of a class that extends WP_UnitTestCase which extends PHPUnit_Framework_TestCase. Being wrapped in this class gives the tests access to assertions and object factories, and runs setUp and tearDown methods so that each test is independent of the others.

1 Answer 1

1

Let me start by saying that the init action is called when WordPress is loaded, before the tests are run. So it you are having your plugin/theme loaded with WordPress (by hooking into muplugins_loaded, for example), the register_my_type() method should be getting called, if your constructor is being called before init. (If you aren't loading your plugin that way, have a look at this tutorial.)

So in your unit tests you should be able to do this:

$this->assertTrue( post_type_exists( 'my_post_type' ) );

You could also use get_post_type() to check that the post type was registered with the correct arguments. (This is the same sort of thing I do to check that my shortcodes are registered.)

I wouldn't worry about trying to test that the method was called, although you could check the list of actions in $wp_actions to see if it was hooked up properly. You could also set a class property as a flag when it is called, but I really think all of that's overkill. When it comes to things hooked to actions like init, especially a function like this which only needs to run once, functional tests are your best bet. Check that they've done what they're supposed to do, rather than focusing on trying to test a single unit like whether the method was called.

That said, you could also test that the method registers the post type by deregistering the post type and manually calling the method. WordPress doesn't appear to provide a deregister_post_type() function, so you'd have to mess with the $wp_post_types global directly. You could delete your post type from that and then call your method and check if it is registered again.

3
  • Thanks! I've been able to confirm that the init action is being called. I'm still having problems with initializing the plugin in a test where I need to supply arguments to the constructor. That tutorial is very helpful. It wasn't clear to me before that the tests are loading a completely separate environment. Sep 8, 2014 at 17:19
  • I'm glad it helped. Depending on how your plugin works, you may be able to just reinitialize it by calling the constructor. If that won't really work for you, you may have to run those tests separately and with some extra code to initialize it with the correct arguments. You can categorize your tests by adding the @group my_group_name annotation in the testcase class docblocks. You can then exclude a group in your config, and run it separately with phpunit --group my_group. Then you'll need to detect when that group is being run and initialize the plugin differently.
    – J.D.
    Sep 8, 2014 at 20:48
  • For an example of how to detect what group is being run you can look at this code in WordPress' bootstrap.
    – J.D.
    Sep 8, 2014 at 20:51

Your Answer

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

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