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.

WordPress Multisite Plugin Unit Tests

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.