Jun 27, 2019

When do WordPress Unit Tests Run (At Which Hook?)

Writing unit tests for a WordPress plugin recently had me wondering:

When do WordPress unit tests run?

Meaning, at what point during the WordPress lifecycle are unit tests executed?

I ran some checks and determined that most of the action hooks that run during a typical WordPress page load are also run during unit testing, up to and including the posts_selection hook. The wp hook that comes after that is never reached.

List of Action Hooks that Run

Here is a full breakdown of which action hooks run when PHPUnit unit tests are executed. This list of hooks comes from WP’s Action Reference page.

The hooks shown with a strikethrough are never run, and those without a strikethrough are run.

muplugins_loaded
registered_taxonomy
registered_post_type
plugins_loaded
sanitize_comment_cookies
setup_theme
load_textdomain
after_setup_theme
auth_cookie_malformed
auth_cookie_valid
set_current_user
init
widgets_init
register_sidebar
wp_register_sidebar_widget
wp_default_scripts
wp_default_styles
admin_bar_init
add_admin_bar_menus
wp_loaded
parse_request
send_headers
parse_query
pre_get_posts
posts_selection
wp …and no hooks fire after this point.

So with that knowledge, you can expect that:

  • Code that is hooked to plugins_loaded/init/etc. will be reflected in your unit tests.
  • Code hooked to a hook that is crossed out in the list above or something after posts_selection will not be reflected in your unit tests.

What About the Rest?

Unit Tests are meant to be used to test individual units (classes/methods/functions) of your code in isolation. In order to test functionality during the rest of the WordPress lifecycle, you can take a look at setting up end-to-end tests using Codeception.

How Did I Determine This?

A few people have asked about how I determined which hooks fire during unit tests. My method for doing so was pretty simple. I threw some constant definitions like this into the main file of a plugin I was unit testing:

add_action( 'plugins_loaded', function() {
    define( 'PLUGINS_LOADED_RAN', true );
} );

…then threw some corresponding checks like this into one of my unit test methods:

echo defined('PLUGINS_LOADED_RAN') ? 'plugins_loaded ran' : 'plugins_loaded did NOT run';

Then depending on which of those messages printed to the command line when I ran phpunit, I was able to tell whether or not each hook had been run. Give it a try if you like and please let me know if any updates to the list above need to be made. Thanks!