运行PHPUnit测试后恢复WordPress默认选项

时间:2018-05-06 作者:Sean

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?

我正在测试我的插件,它提供了一个功能,可以一次添加和删除一些角色。我的插件的用户应该只需运行此功能一次,但他们可以选择根本不运行它,因此我设置了两个测试套件(使用WP-CLI的脚手架)来测试转换角色前后的情况。由于角色转换操作对数据库进行了更改,因此我将对已转换角色的测试分离到各自的PHPUnit组中,并在默认情况下排除了该组的运行。为了测试角色转换函数,我必须调用PHPUnit--group role-permissions 旗帜我还可以在没有组的情况下调用PHPUnit,在默认WordPress角色上运行测试。I run into a problem when I run the tests one after the other.

首先,如果我运行默认测试。。。

$> phpunit
[passes]
。。。它们最初通过。如果我运行特殊角色测试。。。

$> phpunit --group role-permissions
[passes]
。。。然后他们也通过了。但如果在此之后再次运行默认测试。。。

$> phpunit
[fails]
。。。它们不再通过。我发现这是因为role-permissions 在再次运行默认测试之前,测试仍存在于测试数据库中。让默认测试再次通过的唯一方法是重新生成默认WordPress测试数据库。

转换角色以便运行role-permissions 测试,我有一些代码wpSetUpBeforeClass. 在测试运行之前,每次PHPUnit执行只运行一次,因此这似乎是放置代码的正确位置。然而,很明显,测试脚手架代码并没有恢复默认值wptests_options 每次运行后的数据库表。

在我的特殊测试运行后,是否有方法恢复数据库中的默认选项,或者运行role-permissions 在他们自己的数据库中进行测试,或者以其他方式防止我遇到的故障?

相关文件的精简版本如下所示,以供参考:

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 个回复
最合适的回答,由SO网友:J.D. 整理而成

tl;dr:有没有办法在PHPUnit测试套件执行期间更改WordPress选项,并在执行下一个测试套件之前将更改恢复为WordPress默认值,而无需编写自定义的拆卸函数?

是的,也不是。

否,您不能使用当前拥有的代码并期望得到此结果。测试套件使用事务并在每次测试后自动回滚数据库。但你正在改变wpSetUpBeforeClass(), 在事务开始之前运行。你在这里做什么wpSetUpBeforeClass() 你必须把自己清理干净wpTearDownAfterClass(). 这是故意的。

但是,您不必使用wpSetUpBeforeClass(). 你可以把代码放在setUp() 相反通过调用parent::setUp() 在进行更改之前,数据库事务将已经启动,因此您的更改将在每个测试完成后自动回滚。

SO网友:Sean

在马克·卡普伦的评论之后,我在WordPress测试源代码中做了一些挖掘,发现_delete_all_data function 每次测试后运行:

function _delete_all_data() {
    global $wpdb;
    foreach ( array(
        $wpdb->posts,
        $wpdb->postmeta,
        $wpdb->comments,
        $wpdb->commentmeta,
        $wpdb->term_relationships,
        $wpdb->termmeta,
    ) as $table ) {
        $wpdb->query( "DELETE FROM {$table}" );
    }
    foreach ( array(
        $wpdb->terms,
        $wpdb->term_taxonomy,
    ) as $table ) {
        $wpdb->query( "DELETE FROM {$table} WHERE term_id != 1" );
    }
    $wpdb->query( "UPDATE {$wpdb->term_taxonomy} SET count = 0" );
    $wpdb->query( "DELETE FROM {$wpdb->users} WHERE ID != 1" );
    $wpdb->query( "DELETE FROM {$wpdb->usermeta} WHERE user_id != 1" );
}
如您所见,此功能仅还原(从技术上删除)删除帖子、评论、术语和用户。选项和其他站点配置内容不会还原。

我发现解决问题的方法是在更改角色选项之前对其进行备份,然后将其还原。这不是我想要的解决方案,但似乎是最好的解决方案。首先,我定义了在所有测试运行之前和之后运行一次的类设置和拆卸方法:

public static function wpSetUpBeforeClass( $factory ) {
    self::convert_roles();
}

public static function wpTearDownAfterClass() {
    self::reset_roles();
}
然后我定义了创建新角色的函数,并在之前将它们重置为默认值。对于这些,我需要在类中定义一些静态变量。

/**
 * Convert user roles for the tests in this class.
 * 
 * This only works when the current blog is the one being tested.
 */
private static function convert_roles() {
    global $wpdb, $my_tool;

    // role settings name in options table
    self::$role_key = $wpdb->get_blog_prefix( get_current_blog_id() ) . \'user_roles\';

    // copy current roles
    self::$default_roles = get_option( self::$role_key );

    // convert roles
    $my_tool->convert_roles();
}

/**
 * Reset changes made to roles
 */
private static function reset_roles() {
    update_option( self::$role_key, self::$default_roles );

    // refresh loaded roles
    self::flush_roles();
}

/**
 * From WordPress core\'s user/capabilities.php tests
 */
private static function flush_roles() {
    // we want to make sure we\'re testing against the db, not just in-memory data
    // this will flush everything and reload it from the db
    unset( $GLOBALS[\'wp_user_roles\'] );
    global $wp_roles;
    $wp_roles = new WP_Roles();
}
类中的静态变量可以定义如下:

protected static $role_key;
protected static $default_roles;
现在,我的测试通过了,不管它们被称为什么顺序。

结束

相关推荐

WP-CLI从特定的职位类型和分类术语获取所有职位

我试图从自定义分类法中的特定帖子类型和术语中选择所有帖子,但我所做的任何尝试都只会得到特定帖子类型中所有帖子的列表wp post list --post_type=custom-type --fields=post_name,ID 这将返回cpt中的所有帖子custom-type, 但如果说我只想列出id为49的帖子,我试过了wp post list --post_type=custom-type --taxonomy=custom-tax --terms=49 --fields=post_na