web-dev-qa-db-fra.com

Wordpress Unit Testing - Impossible de créer des tableaux

J'utilise PHPUnit pour tester un peu mon WP plug-in au-dessus de la suite de tests WP. Tout fonctionne bien sauf que lorsque j'essaie de créer une table via la méthode setUp, la table n'est pas créée.

Voici mon code:

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

}

La classe PAO_UnitTestCase est simplement une extension de la classe WP_UnitTestCase qui contient une méthode - la méthode el - qui enregistre simplement le contenu dans un fichier de mon choix.

Comme vous pouvez le voir, j’ai utilisé la méthode el pour

  1. Ecrivez la réponse de dbDelta dans le journal
  2. Écrire les noms de toutes les tables existantes dans le journal

Selon le journal, dbDelta a pu créer la table, mais celle-ci ne fait pas partie des tables existantes.

Donc mes questions sont:

  1. Est-il possible de créer des tables lors des tests unitaires via PHPUnit?
  2. Si oui, qu'est-ce que je fais mal?

J'espère que quelqu'un pourra m'aider.

Merci!

Mise à jour: Comme indiqué dans la discussion et la réponse acceptée ci-dessous, les tables sont créées mais en tant que tables TEMPORARY. Vous ne pourrez pas voir les tables via SHOW TABLES, mais vous vérifiez son existence en insérant une ligne, puis en essayant de la récupérer.

5
Paolo

Vous venez de découvrir une fonctionnalité importante de la suite de tests principale: elle force toutes les tables créées lors du test à être des tables temporaires.

Si vous regardez dans la méthode WP_UnitTestCase::setUp(), vous verrez que il appelle une méthode appelée start_transaction() . That méthode start_transaction() démarre une transaction de base de données MySQL :

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

Ainsi, toutes les modifications apportées par votre test à la base de données peuvent simplement être annulées par la suite dans la méthode tearDown() . Cela signifie que chaque test commence par une base de données WordPress vierge, non altérée par les tests précédents.

Cependant, vous remarquerez que start_transaction() rattache également deux méthodes au filtre 'query' : _create_temporary_tables et _drop_temporary_tables. Si vous examinez la source de ces méthodes , vous verrez qu'elles font en sorte que les requêtes de table CREATE ou DROP soient plutôt des tables temporaires:

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

Le filtre 'query' est appliqué à toutes les requêtes de base de données transmises via $wpdb->query(), que dbDelta() utilise . Cela signifie donc que lorsque vos tables sont créées, elles le sont sous la forme de tables temporaires.

Donc, afin de lister ces tables, Je pense que vous devriez plutôt afficher les tables temporaires: $sql = "SHOW TEMPORARY TABLES LIKE '%'";

Update: MySQL ne vous permet pas de lister les tables temporaires comme vous pouvez le faire avec les tables normales. Vous devrez utiliser une autre méthode pour vérifier si la table existe, par exemple en essayant d'insérer une ligne.

Mais pourquoi le cas de test unitaire nécessite-t-il la création de tables temporaires? N'oubliez pas que nous utilisons des transactions MySQL pour que la base de données reste propre. Cependant, nous ne voulons pas jamais engager les transactions, nous voulons toujours les annuler à la fin du test. Mais il y a certaines instructions MySQL qui vont causer un implicite commit . Parmi ceux-ci, vous l'avez deviné, CREATE TABLE et DROP TABLE. Cependant, selon la documentation MySQL:

Les instructions CREATE TABLE et DROP TABLE ne commettent pas de transaction si le mot clé TEMPORARY est utilisé.

Par conséquent, pour éviter une validation implicite, le scénario de test force toutes les tables créées ou supprimées à être des tables temporaires.

Ce n'est pas une fonctionnalité bien documentée, mais une fois que vous comprenez ce qui se passe, il devrait être assez facile de travailler avec.

9
J.D.