2

I've written a module that reads a csv of user records and imports them into Drupal 6 using the Batch API. The Batch API operations callback basically just does a user_save(). It works fine when I test it manually. I'm now writing a SimpleTest to verify it.

What I've found is that when I run my test (which extends DrupalWebTestCase), it actually creates new users in my primary Drupal's tables, rather than into the "simpletest" prefixed tables. I suspect this has something to do with the combination of SimpleTest and the Batch API.

Has anyone experienced this before?

SimpleTest 6.x-2.11 Drupal 6.22

Edit: Adding a very simple test case that duplicates the problem. After running the SimpleTest, my primary Drupal site will have 3 new users (u1, u2, u3) created in it. The test will fail, because no users will be created in the 'simpletest*' prefixed tables.

Module code:

function user_import_batch($user_data) {
  $batch = array(
    'title' => t('Importing users'),
    'operations' => array(
      array('userimport_process', array($user_data))
    ),
    'progress_message' => '',
    'finished' => 'userimport_finished',
  );
  batch_set($batch);
}

function userimport_process($user_data, &$context) {
  // Initialize
  if (empty($context['sandbox']['progress'])) {
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['max'] = count($user_data);
    $context['results'] = array();
  }

  // Process max 20 users at a time
  $processed = 0;
  while ($context['sandbox']['progress'] < $context['sandbox']['max'] && $processed < 20) {
    $index = $context['sandbox']['progress'];

    // create user
    $account = user_save('', $user_data[$index]);

    $context['sandbox']['progress']++;
    $processed++;
  }
  $context['sandbox']['import_object'] = serialize($Import);

  // Finished yet?
  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
  }
}

Simpletest code:

class ImportTestCase extends DrupalWebTestCase {
  protected $privileged_user;

  public static function getInfo() {
    return array(
      'name' => 'User Import Test',
      'description' => 'Test',
      'group' => 'User Import Test',
    );
  }

  public function setUp() {
    parent::setUp();

    // Create and log in our privileged user.
    $permissions = array(
      'administer users',
    ); 
    $this->privileged_user = $this->drupalCreateUser($permissions); // user id 3
    $this->drupalLogin($this->privileged_user);
  }

   public function testAddUsers() {
     // import 3 users
     $user_data = array(
       array(
         'name' => 'u1',
         'mail' => 'u1@example.com',
         'pass' => 'password'
       ),
       array(
         'name' => 'u2',
         'mail' => 'u2@example.com',
         'pass' => 'password'
       ),
       array(
         'name' => 'u3',
         'mail' => 'u3@example.com',
         'pass' => 'password'
       ),
     );

     user_import_batch($user_data);

     // verify that the users have been created
     // this will fail, as the users will be created in the host site that is running the SimpleTest
     $imported_count = db_result(db_query('SELECT count(uid) FROM {users} WHERE name LIKE "u1" OR name LIKE "u2" OR name LIKE "u3"'));
     $this->assertEqual(count($user_data), $imported_count, 'Imported users appear in users table. Found ' . $imported_count);
   }
}
1

Running batch API in tests should work just fine, although there is an issue with the testbot.

Make sure you are always using curly braces for your tables, that's the usual issue when something like this happens. So for example SELECT * FROM {node}.

Edit:

Two things wrong with your code, as written in the comments.

  1. You are not calling batch_process() in your code, so the batch is never executed within the tests.

  2. My initial answer was not 100% correct. You can not trigger batch runs directly within your test code. A batch requires direct interaction with the browser and it is not possible to run tested batches (simpletest is already running as a batch run). What you need to do is create a test module, implement hook_menu() with a page callback and then call batch_set()/batch_process() there.

  • Thanks for the reply. That's the funny thing, my code calls user_save() and never executes queries that write to the database, so {} is not the issue. I'm also not using testbot (this is local dev). – rcourtna Oct 28 '11 at 14:40
  • Show your (test) code then... – Berdir Oct 28 '11 at 20:43
  • Hi, I've dumbed down my code a great deal and have created a bare-bones test case that duplicates the problem. Code posted in the Question description. – rcourtna Oct 29 '11 at 15:25
  • Your batch is not run at all. batch_set() is not enough unless called in a form submit function. In code like this, you need to call batch_process() as well. See api.drupal.org/api/drupal/includes--form.inc/group/batch/7. I assume this is the actual issue here and the users in your main database are just a left-over or something like that. – Berdir Oct 29 '11 at 16:14
  • Ignore the last sentence. The second problem then is probably that you override the batch information from simpletest itself because this is statically cached. Updated my answer. – Berdir Oct 29 '11 at 16:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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