WordPress单元测试-无法创建表

时间:2016-03-10 作者:Paolo

我正在使用PHPUnit在WP测试套件的顶部对我的WP插件进行单元测试。一切正常,只是当我尝试通过setUp方法创建表时,无法创建表。

这是我的代码:

class Test_Db extends PAO_UnitTestCase {

function setUp() {

    parent::setUp();

    global $wpdb;

    $sql = "CREATE TABLE {$wpdb->prefix}mytest (
            id bigint(20) NOT NULL AUTO_INCREMENT,
            column_1 varchar(255) NOT NULL,
            PRIMARY KEY  (id)
        ) ENGINE=MyISAM";

    require_once ABSPATH . \'wp-admin/includes/upgrade.php\';
    $this->el(dbDelta($sql));

}

function tearDown() {
    parent::tearDown();
}

function test_db_stuff(){

    global $wpdb;

    $sql = "SHOW TABLES LIKE \'%\'";
    $results = $wpdb->get_results($sql);

    foreach($results as $index => $value) {
        foreach($value as $tableName) {
            $this->el($tableName);
        }
    }
}

}
PAO\\u UnitTestCase类只是WP\\u UnitTestCase类的一个扩展,它包含一个方法,即el方法,该方法只需将任何内容记录到我选择的文件中。

如你所见,我使用el方法

将dbDelta的响应写入日志将所有现有表的名称写入日志根据日志,dbDelta能够创建该表,但未作为现有表的一部分列出。

所以我的问题是:

是否可以在单元测试期间通过PHPUnit创建表

谢谢

Update: 正如下面的讨论和公认的答案所示,这些表确实是创建的,但作为临时表。虽然您无法通过SHOW tables查看这些表,但可以通过插入一行,然后尝试检索该行来检查其存在性。

1 个回复
最合适的回答,由SO网友:J.D. 整理而成

您刚刚发现了核心测试套件的一个重要特性:它强制在测试期间创建的任何表都是临时表。

如果你看看WP_UnitTestCase::setUp() 方法你会看到it calls a method called start_transaction(). 那个start_transaction() method 启动MySQL database transaction:

        function start_transaction() {
                global $wpdb;
                $wpdb->query( \'SET autocommit = 0;\' );
                $wpdb->query( \'START TRANSACTION;\' );
                add_filter( \'query\', array( $this, \'_create_temporary_tables\' ) );
                add_filter( \'query\', array( $this, \'_drop_temporary_tables\' ) );
        }
它这样做是为了您的测试在数据库中所做的任何更改都可以rolled back afterward in the tearDown() method. 这意味着每个测试都从一个干净的WordPress数据库开始,不受之前测试的污染。

但是,您会注意到start_transaction() 还将两个方法挂接到\'query\' filter: _create_temporary_tables_drop_temporary_tables. 如果你看the source of these methods, 你会发现他们CREATEDROP 改为针对临时表的表查询:

        function _create_temporary_tables( $query ) {
                if ( \'CREATE TABLE\' === substr( trim( $query ), 0, 12 ) )
                        return substr_replace( trim( $query ), \'CREATE TEMPORARY TABLE\', 0, 12 );
                return $query;
        }

        function _drop_temporary_tables( $query ) {
                if ( \'DROP TABLE\' === substr( trim( $query ), 0, 10 ) )
                        return substr_replace( trim( $query ), \'DROP TEMPORARY TABLE\', 0, 10 );
                return $query;
        }
The\'query\' 过滤器应用于通过的所有数据库查询$wpdb->query(), which dbDelta() uses. 这意味着在创建表时,它们将被创建为临时表。

因此,为了列出这些表,我认为您必须显示临时表:$sql = "SHOW TEMPORARY TABLES LIKE \'%\'";

Update: MySQL不允许您像列出常规表一样列出临时表。您必须使用另一种方法检查表是否存在,例如尝试插入行。

但是为什么单元测试用例首先需要创建临时表呢?请记住,我们正在使用MySQL事务,以便数据库保持干净。但是,我们不想提交事务,我们希望总是在测试结束时回滚它们。但是有some MySQL statements that will cause an implicit commit. 其中包括,你猜对了,CREATE TABLEDROP TABLE. 但是,根据MySQL文档:

CREATE TABLEDROP TABLE 如果TEMPORARY 使用关键字。

因此,为了避免隐式提交,测试用例强制创建或删除的任何表都是临时表。

这不是一个文档化很好的特性,但一旦您了解了发生了什么,应该很容易使用它。