web-dev-qa-db-ja.com

Wordpressの単体テスト - テーブルを作成できない

私はWPテストスイートの上にある私のWPプラグインをユニットテストするためにPHPUnitを使っています。 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_UnitTestCaseは、単純にWP_UnitTestCaseクラスを拡張したもので、1つのメソッド(elメソッド)が含まれています。これは、選択したファイルに単純に何でも記録します。

ご覧のとおり、私はelメソッドを使用して

  1. DbDeltaの応答をログに書き込む
  2. 既存のすべてのテーブルの名前をログに書き込む

ログによると、dbDeltaはテーブルを作成できましたが、既存のテーブルの一部としてリストされていません。

だから私の質問は次のとおりです。

  1. PHPUnitによるユニットテスト中にテーブルを作成することは可能ですか?
  2. もしそうなら、私は何を間違っているのですか?

誰かが私を助けることができると思います。

ありがとうございます。

更新: 以下の議論と受け入れられた答えに見られるように、テーブルは作成されますがTEMPORARYテーブルとして。 SHOW TABLESでテーブルを見ることはできませんが、行を挿入してから行を検索してその存在を確認します。

5
Paolo

コアテストスイートの重要な機能を発見しました。テスト中に作成されたすべてのテーブルを一時テーブルに強制します。

WP_UnitTestCase::setUp()メソッドを見ると、 start_transaction()というメソッドを呼び出している がわかります。 start_transaction() methodMySQLデータベーストランザクション を開始します:

        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' ) );
        }

これにより、テストでデータベースに加えられた変更を tearDown()メソッドで後でロールバック することができます。つまり、各テストは、以前のテストで汚染されていない、きれいなWordPressデータベースで開始されます。

ただし、start_transaction()は2つのメソッドを 'query'フィルター_create_temporary_tablesおよび_drop_temporary_tablesにもフックすることに注意してください。 これらのメソッドのソース を見ると、CREATEまたはDROPテーブルクエリが一時テーブル用であることがわかります。

        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;
        }

'query'フィルタは、$wpdb->query()dbDelta()が使用する を介して渡されるすべてのデータベースクエリに適用されます。つまり、テーブルが作成されると、それらはtemporaryテーブルとして作成されます。

したがって、これらのテーブルをリストするには、 代わりに一時テーブルを表示する必要があると思います:$sql = "SHOW TEMPORARY TABLES LIKE '%'";

更新:MySQLでは、通常のテーブルと同様に一時テーブルをリストすることはできません。行の挿入を試みるなど、テーブルが存在するかどうかを確認する別の方法を使用する必要があります。

しかし、なぜユニットテストケースでは、最初に一時テーブルを作成する必要があるのですか?データベースをクリーンな状態に保つために、MySQLトランザクションを使用していることに注意してください。ただし、トランザクションをコミットすることは望みません。テストの終了時には常にロールバックしたいと考えています。しかし、 implicitcommit を引き起こすMySQLステートメントがいくつかあります。これらの中には、CREATE TABLEDROP TABLEという推測があります。ただし、MySQLのドキュメントによると:

TEMPORARYキーワードが使用されている場合、CREATE TABLEおよびDROP TABLEステートメントはトランザクションをコミットしません。

したがって、暗黙的なコミットを回避するために、テストケースは作成または削除されたテーブルを一時テーブルに強制します。

これは十分に文書化された機能ではありませんが、何が起こっているのかを理解したら、作業がかなり簡単になります。

10
J.D.