Отмените настройки WordPress по умолчанию после выполнения теста PHPUnit


Tl;dr: есть ли способ внести изменения в параметры WordPress во время выполнения набора тестов PHPUnit и вернуть изменения к настройкам WordPress по умолчанию до выполнения следующего набора тестов без написания пользовательской функции удаления?

Я тестирую свой плагин, который предоставляет функцию для добавления и удаления нескольких ролей одновременно. Пользователям моего плагина нужно будет запустить эту функцию только один раз, но они могут вообще не запускать ее, поэтому я настройте два набора тестов (с использованием каркасов WP-CLI), чтобы проверить ситуацию как до, так и после преобразования ролей. Поскольку операция преобразования ролей вносит изменения в базу данных, я разделил тесты для преобразованных ролей на их собственную группу PHPUnit и исключил эту группу из запуска по умолчанию. Поэтому, чтобы протестировать функцию смены ролей, я должен вызвать PHPUnit с флагом --group role-permissions. Я также могу запустить тесты для ролей WordPress по умолчанию, вызвав PHPUnit без группы. Я бегу в проблему, когда я запускаю тесты один за другим.

Во-первых, если я выполню тесты по умолчанию...

$> 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>
...
Author: Sean, 2018-05-06

2 answers

Tl;dr: есть ли способ внести изменения в параметры WordPress во время выполнения набора тестов PHPUnit и вернуть изменения к настройкам WordPress по умолчанию до выполнения следующего набора тестов без написания пользовательской функции удаления?

Да и нет.

Нет, вы не можете использовать имеющийся у вас код и ожидать такого результата. Набор тестов действительно использует транзакции и автоматически откатывает базу данных после каждого теста. Но вы вносите свои изменения в wpSetUpBeforeClass(), который выполняется до начала транзакции. Все, что вы делаете в wpSetUpBeforeClass(), вы должны привести себя в порядок в wpTearDownAfterClass(). Это сделано специально.

Однако вам не обязательно использовать wpSetUpBeforeClass(). Вместо этого вы могли бы просто поместить свой код в setUp(). При вызове parent::setUp() перед внесением изменений транзакция базы данных уже будет запущена, и поэтому ваши изменения будут автоматически откатываться после завершения каждого теста.

 2
Author: J.D., 2018-05-07 13:12:08

После комментария Марка Каплуна я немного покопался в исходном коде теста WordPress и нашел _delete_all_data функция, которая запускается после каждого теста:

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;

Теперь мои тесты проходят независимо от того, в каком порядке они проходят называемый.

 3
Author: Sean, 2018-05-07 07:51:12