3

One of the things that my plugin does is creates a number of SQL tables as part of a versioning function (that is run under the admin_init hook as I couldn't find a better wordpress way of doing things). I call the initialisation script as part of the setUp routine and theorectically should be dropped as part of the tearDown routine.

In essence here is the basic stub of what I'm (unsuccessfully) doing:

class GFDL_test extends WP_UnitTestCase {
public $plugin_slug = 'gfdl';
protected $users = array();

function setUp() {
    parent::setUp();
    include_once(/* path for gfdl_versioning function*/);
    GFDataLayer::init_globals();
    gfdl_versioning(); /* this creates the tables */

    /* add test users (to give them a role add a 'role' parameter to this add user) */
    $this->users[0] = wp_insert_user(array('user_login' => 'test1'));
    $this->users[1] = wp_insert_user(array('user_login' => 'test2'));
}

function tearDown() {
    global $wpdb;
    /* these lines don't work for some reason */
    $wpdb->query('DROP TABLE IF EXISTS ' . $wpdb->prefix . 'gfdl_bullets;');
    $wpdb->query('DROP TABLE IF EXISTS ' . $wpdb->prefix . 'gfdl_character_ai;');
    $wpdb->query('DROP TABLE IF EXISTS ' . $wpdb->prefix . 'gfdl_items;');
    $wpdb->query('DROP TABLE IF EXISTS ' . $wpdb->prefix . 'gfdl_sprites;');
    $wpdb->query('DROP TABLE IF EXISTS ' . $wpdb->prefix . 'gfdl_backgrounds;');

    wp_delete_user($this->users[0]);
    wp_delete_user($this->users[1]);
    parent::tearDown();
}

function testDatalayer() {
    $this->assertTrue(class_exists( 'GFDataLayer'));
}

function testVersion() {
    $this->assertEquals('0.11', get_option('gfdl_version'));
}
}

The tear down function appears to be executing but the drop tables aren't working (they remain after the unit tests are finished).

My first thought is that the tests were being executed asynchronously but my debugging is suggesting otherwise.

Is there a better way in handling plugin upgrades (in respect to database changes) or is there something that I'm missing?

2
  • It is hard to guess reasons for "don't work"... Is code getting executed? Are SQL queries valid? Are they reaching database? etc...
    – Rarst
    Commented May 27, 2013 at 13:18
  • As mentioned in the question, the teardown function appears to be executing (at one stage I had an echo statement in the teardown which was echoed to the console that phpunit writing to) but the tables are still there at the end of the test (causing problems when I try to re-create them in the setUp method). Commented May 27, 2013 at 21:27

2 Answers 2

4

The unit tests transform all CREATE TABLE and DROP TABLE queries to CREATE TEMPORARY TABLE and DROP TEMPORARY TALBE, respectively. So in your tearDown the query will attempt to drop temporary tables with those names, but not the actual tables. To fix this, add this before your DROP queries:

remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );

You may also need to add this before your CREATE TABLE queries:

remove_filter( 'dbdelta_create_queries', array( $this, '_create_temporary_tables' ) );

The WP_UnitTestCase::_create_temporary_tables() function is the one that filters the queries to make tables temporary. It is added in the setUp(), and removed in the tearDown().

Update:

The _create_temporary_tables() function is now hooked to the 'query' filter, instead of 'dbdelta_create_queries'. See changeset 27041. So now to remove it you would do:

remove_filter( 'query', array( $this, '_create_temporary_tables' ) );
5
  • As is, it isn't working for me. I'm wondering if that is something to do with $this not being an instance of WP_UnitTestCase ($this is an object that is inherited from it). If I move parent::tearDown(); above the drop table statements, they work, but I'm worried about other effects. Commented Sep 24, 2013 at 5:07
  • Ahh... you need to use remove_filter( 'query', array( $this, '_drop_temporary_tables' ) ); too. I've updated my answer. `
    – J.D.
    Commented Sep 24, 2013 at 13:04
  • This is not directly related, but another thing to watch out for when using WordPress APIs under test is the "Object Cache", if you bypass an API by executing SQL, you should probably do a wp_cache_flush()
    – farinspace
    Commented Sep 6, 2014 at 17:39
  • 1
    @farinspace — That's true, although WordPress's test framework will automatically do this before each test.
    – J.D.
    Commented Sep 6, 2014 at 21:18
  • +1 for the link to WP_UnitTestCase .. my scenario was an edge case with both API and wpdb queries in a single test
    – farinspace
    Commented Sep 7, 2014 at 19:06
1

Have you tried to execute the SQL statements manually ? You would perhaps see an error message preventing the table DROP command to execute (like insufficient rights).

Normally, the SQL tables creating is done in the activation hook and SQL tables drops in deactivation hook.

And yes, WP has a mechanism to automatically update tables structure based on the plugin version number.

1
  • The drop table SQL worked fine (assuming I got $wpdb->prefix right). Rights is not an issue as I'm running the queries as root (it is on my local machine). That mechanism seems fine for the structure, but I'm not sure how it would handle changing data inside the tables (for testing purposes). Upvoted as it is a good way of how things should be done. Commented Jul 2, 2013 at 0:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.