12.8. WordPress Multisite Plugin Unit Tests
In the previous blogs we covered single site unit tests. In this concluding blog of the series, we explain WordPress Multisite Plugin unit tests.
As explained earlier, WordPress Test Lib creates an in-memory WordPress instance to run unit tests. The test instance is actually a WordPress single site installation and it is not useful to carryout the multisite tests.
In Enable WordPress Multisite, we saw how to go about WordPress Multisite Installation wherein we used wp-config.php to convert WordPress installation into multisite installation. The process makes extensive changes to WordPress database and then multisite logic kicks in. This also means that we can’t have both plain installation and multisite installation side by side.
Similarly, WordPress Test Lib has features to create Multisite instance for multisite tests. As with actual installation, here too, we can’t have both single and multisite instance active at the same time. This essentially means that Test Lib can create and handle only one instance during test run - either plain site or a multisite.
Because of this, we need an entirely new PHPUnit configuration to force WordPress Test Lib to create and use WordPress Multisite Installation.
Configure PHPUnit for Multisite
For WordPress Test Lib to create multisite installation, we have to set a PHP constant WP_TESTS_MULTISITE in PHPUnit configuration file.
Earlier, for single site tests, we placed PHPUnit configuration file
phpunit.xml
in top folder of the plugin and we reserve this file
exclusively for single site testing. For multisite testing, we use a new
PHPUnit configuration file named multisite.xml
under tests/phpunit
folder. The multisite.xml file is similar to phpunit.xml except that in
multisite.xml we define the constant WP_TESTS_MULTISITE.
share-on-social/tests/phpunit/multisite.xml
<phpunit bootstrap="bootstrap.php" backupGlobals="false" colors="false"
convertErrorsToExceptions="true" convertNoticesToExceptions="true"
convertWarningsToExceptions="true">
<php>
<const name="WP_TESTS_MULTISITE" value="1" />
</php>
<testsuites>
<testsuite>
<!-- don't change order of next two files -->
<file>tests/test-share-on-social.php</file>
<file>tests/test-admin.php</file>
<file>tests/test-ajax.php</file>
<!-- no order -->
<file>tests/test-sos.php</file>
<file>tests/test-options.php</file>
<file>tests/test-stats.php</file>
<file>tests/test-help.php</file>
<file>tests/test-frontend.php</file>
<file>tests/test-helper.php</file>
<file>tests/test-ajax-others.php</file>
<file>tests/test-uninstall-multisite.php</file>
<!-- need to be last as it breaks mysqli -->
<file>tests/test-activator-multisite.php</file>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>ajax</group>
</exclude>
</groups>
</phpunit>
Multisite tests are defined in separate test case files - tests/test-uninstall-multisite.php
and
tests/test-activator-multisite.php
. We add these test files in
<testsuite> element of multisite.xml
.
Note
We can also define WP_TESTS_MULTISITE in WordPress Test Lib config
file tests/phpunit/wp-tests-config.php
as explained in WordPress Core Handbook. But we prefer multisite.xml as it allows us to add separate set of multisite test files to test suite.
When you run phpunit for single site it shows the message - To run
multisite, use -c tests/phpunit/multisite.xml. For this reason, we
place multisite.xml in tests/phpunit directory. Tests will go through
even when it is in top folder, but we go with the WordPress standard and
place it in tests/phpunit
folder.
Execute Multisite tests with following command.
$ phpunit -c tests/phpunit/multisite.xml
Multisite Tests
When we run PHPUnit using multisite.xml, WordPress Test Lib creates an
instance of WordPress Multisite. However, it will have only one default
site. For tests, we require one more site in the network and to add
additional site, we use WP_UnitTestCase::add_blog()
method in test
case setup()
method.
share-on-social/tests/phpunit/tests/test-activator-multisite.php
class Test_Sos_Activator extends WP_UnitTestCase {
public function setup () {
parent::setup();
// create sos post type
require_once 'admin/class-sos.php';
$this->sos = new Sos();
require_once 'admin/class-activator.php';
$this->activator = new Sos_Activator();
// add one more blog to the site
$this->add_blog( 'test1', 'Test 1' );
// set default admin - some test change user
wp_set_current_user( 1 );
Util::set_admin_role( true );
}
In the multisite tests, we use following construct to fetch blogs and switch between them. The WordPress function wp_get_sites() returns an array of blogs i.e. sites in the multisite network.
$blogs = wp_get_sites();
$this->assertCount( 2, $blogs );
switch_to_blog( $blogs[ 1 ][ 'blog_id' ] );
.... some test
restore_current_blog();
switch_to_blog( $blogs[ 1 ][ 'blog_id' ] );
.... repeat the test in blog 2
restore_current_blog();
One such multisite test from Test_Sos_Activator is shown in the next snippet.
share-on-social/tests/phpunit/tests/test-activator-multisite.php
public function test_multisite_activate_by_superadmin () {
// list of blogs in site
$blogs = wp_get_sites();
$this->assertCount( 2, $blogs );
// networkwide activation - superadmin
$networkwide = true;
// create locker and no options
switch_to_blog( $blogs[ 0 ][ 'blog_id' ] );
Util::set_activate_plugins_cap( true );
$this->sos->create_post_type();
$post_id = Util::get_post_id( 'sos', 'locker_id', 'basic' );
$this->assertTrue( isset( $post_id ) );
$options = get_option( 'sos_common_options' );
$this->assertFalse( $options );
restore_current_blog();
switch_to_blog( $blogs[ 1 ][ 'blog_id' ] );
Util::set_activate_plugins_cap( true );
$this->sos->create_post_type();
$post_id = Util::get_post_id( 'sos', 'locker_id', 'basic' );
$this->assertTrue( isset( $post_id ) );
$options = get_option( 'sos_common_options' );
$this->assertFalse( $options );
restore_current_blog();
// we can't remove super admin status from default user so create new
// user
$user_id = $this->add_user( 'testuser' );
wp_set_current_user( $user_id );
// grant super admin and activate
grant_super_admin( $user_id );
$this->activator->activate( $networkwide );
// test activation - locker deleted, options created
switch_to_blog( $blogs[ 0 ][ 'blog_id' ] );
$post_id = Util::get_post_id( 'sos', 'locker_id', 'basic' );
$this->assertFalse( isset( $post_id ) );
$options = get_option( 'sos_common_options' );
$this->assertNotFalse( $options );
$this->assertCount( 1, $options );
$this->assertSame( SOS_VERSION, $options[ 'version' ] );
restore_current_blog();
switch_to_blog( $blogs[ 1 ][ 'blog_id' ] );
$post_id = Util::get_post_id( 'sos', 'locker_id', 'basic' );
$this->assertFalse( isset( $post_id ) );
$options = get_option( 'sos_common_options' );
$this->assertNotFalse( $options );
$this->assertCount( 1, $options );
$this->assertSame( SOS_VERSION, $options[ 'version' ] );
restore_current_blog();
}
Tests in multisite test files - test-activator-multisite.php and test-uninstall-multisite.php - follow similar pattern.
With that, we are at the end of WordPress Plugin Development Tutorial series.