Revert WordPress default options after a PHPUnit test has run

tl;dr: is there a way to make changes to WordPress options during a PHPUnit test suite execution, and have the changes reverted to the WordPress defaults before the next test suite is executed, without writing a custom teardown function?

I’m testing my plugin which provides a function to add and remove some roles all at once. The users of my plugin should only have to run this function once, but they can choose not to run it at all, so I set up two test suites (using WP-CLI’s scaffolding) to test the situation both before and after converting roles. Since the role conversion operation makes changes to the database, I separated the tests on the converted roles into their own PHPUnit group, and excluded this group from running by default. To test the role changing function, I therefore have to call PHPUnit with the --group role-permissions flag. I can also run the tests on the default WordPress roles by calling PHPUnit without a group. I run into a problem when I run the tests one after the other.

First, if I run the default tests…

$> phpunit
[passes]

…they initially pass. If I then run the special roles tests…

$> phpunit --group role-permissions
[passes]

…then they also pass. But if I run the default tests again after this…

$> phpunit
[fails]

…they no longer pass. I found that this is because the options changed by the role-permissions tests are still present in the test database before the default ones are run again. The only way I can get the default tests to pass again is to regenerate the default WordPress test database.

To convert the roles so I can run the role-permissions tests, I have some code in wpSetUpBeforeClass. This runs only once per PHPUnit execution, before tests are run, so this seems like the right place to put the code. However, clearly the test scaffolding code does not restore the default wptests_options database table after each run.

Is there a way to restore the default options in the database after my special tests have run, or run my role-permissions tests in their own database, or some other way to prevent the failures I get?

For reference, the stripped down versions of the relevant files are shown below:

tests/test-default-roles.php:

/**
 * // no special group
 */
class OtherTests extends WP_UnitTestCase {    
    public function test_default_roles() {
        // test stuff with the default WordPress roles
    }
}

tests/test-new-roles.php:

/**
 * @group role-permissions
 */
class RoleTests extends WP_UnitTestCase {
    /**
     * Convert roles before running any test
     * (this changes the wp_settings table)
     */
    public static function wpSetUpBeforeClass( $factory ) {
        // convert roles
        global $my_tool;
        $my_tool->convert_roles();
    }

    public function test_new_roles() {
        // test some stuff to do with the converted roles
    }
}

phpunit.xml

...
<testsuites>
    <testsuite>
        <directory prefix="test-" suffix=".php">./tests/</directory>
    </testsuite>
</testsuites>
<groups>
    <exclude>
        <!-- exclude role conversion tests from running by default -->
        <group>role-permissions</group>
    </exclude>
</groups>
...

2 Answers
2

tl;dr: is there a way to make changes to WordPress options during a PHPUnit test suite execution, and have the changes reverted to the WordPress defaults before the next test suite is executed, without writing a custom teardown function?

Yes, and no.

No, you cannot use the code you currently have and expect this result. The test suite does use transactions and automatically roll back the database after each test. But you are making your changes in wpSetUpBeforeClass(), which runs before the transaction begins. Anything you do in wpSetUpBeforeClass() you have to clean up yourself in wpTearDownAfterClass(). This is by design.

However, you don’t have to use wpSetUpBeforeClass(). You could just place your code in setUp() instead. By calling parent::setUp() before making your changes, the database transaction will already have started and so your changes will be rolled back automatically after each test is complete.

Leave a Comment