Everon's avatar

[Solved] TestDummy and Codeception with SQLite in memory error - Integrity constraint 19

Hi guys,

I followed both the latest Test Dummy and SQLite in memory lessons and tried to implement an integration test for a user repository to make sure every thing works as planned.

To start off, here's the migration for the table.

$table->increments('id');
$table->char('username', 32)->unique();
$table->char('password', 64);
$table->char('remember_token', 128)->nullable();
$table->nullableTimestamps(); //For SQLite

I found an error with the timestamps not working and fixed that no problem but when I run my tests with Test Dummy using the times(int); method I'll get the following error

Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: users.id (SQL: insert into "users" ("id", "username", "password", "updated_at", "created_at") values (267, ztorp, y$hpDQnOccwaMElFt8j3YUAu1RrqMmCs6NJPR.1VyjeZbNZ21TGTBwS, 2014-12-24 11:21:45, 2014-12-24 11:21:45))

And here is the factory for Users:

$factory('User', [
 'id' => $faker->randomNumber(),
    'username' => $faker->userName,
    'password' => Hash::make($faker->word)
]);

And finally the test that the error comes from:

Factory::times(5)->create('User');
    $users = $this->repo->getAllUsers();
    $this->assertInternalType('array', $users);
    $this->assertCount(5, $users);

I've tried to ensure that the user.id field is unique by playing around a lot with the id field of the User factory for Test Dummy but with little to no luck.

Whilst it makes the real test fail, the error doesn't appear when removing the times method, repeating create() over and over will still produce the error.

The tests work perfectly when running MySQL but for the sake of improving the speed of the tests I'd like to get the SQLite memory database working correctly.

Any ideas guys?

0 likes
4 replies
Everon's avatar
Everon
OP
Best Answer
Level 2

Ok, from looking over the lessons again - I made a mistake with both the creation of the factories and the tests. The ID doesn't have to be specified in the factory or the test (in the case of testing we can get a user by ID).

Updated factory:

$factory('User', [
//'id' => $faker->uuid,
'username' => $faker->userName,
'password' => Hash::make($faker->word)
]);

Updated test:

public function testItCanGetAUserById()
{
    //Create some users
    $users = Factory::times(5)->create('User');

    $user = $this->repo->getUserById($users[0]->id);

    $this->assertInstanceOf('MBU\Users\UserContract', $user);
    $this->assertSame($users[0]->id, $user->id);
}
JeffreyWay's avatar

Yeah, exactly. The id primary key would auto-increment, so you don't have to explicitly set that. :)

devinfd's avatar

This is usually not necessary but you could also set id = 0. This would allow you to then override the id if for some reason you did need to set it explicitly. If not then mysql will override it to the next auto-increment integer.

Example:

$factory('User', [
    'id' => 0,
    'username' => $faker->userName,
    'password' => Hash::make($faker->word)
]);
Factory::create('User', ['id' => 1]);
alfrednutile's avatar

Is this a shortcoming of sqlite?

We have the same issue and since we are using uuids for the id they do not auto-increment. Also we use them to set our tests so we can verify they actions work

  Scenario: Project PUT
    Given create project with name "Mock Project PUT" and id "mock-project-put"
    When I request "GET /api/v1/projects/mock-project-put"
    Then I get a "200" response
    Then the "data.project.name" property equals "Mock Project PUT"
    Given I have the payload:
    """
      { "data":
        {
           "name": "UPDATED Project",
           "id": "mock-project-put"
         }
      }
      """
    And I request "PUT /api/v1/projects/mock-project-put"
    Then I get a "200" response

for example

But we get this error when trying to use TestDummy

app/tests/acceptance/features/projects/projects_api.feature:30
PHP Fatal error:  Uncaught exception 'Exception' with message 'Test Failed PHP Warning:  array_map(): An error occurred while invoking the map callback in /home/rof/src/github.com/alfred-nutile-inc/approve-v2/vendor/laracasts/testdummy/src/Laracasts/TestDummy/Builder.php on

but not if I just use Eloquent to create the record.

    /**
     * @Given /^create project with name "([^"]*)" and id "([^"]*)"$/
     */
    public function createProjectWithNameAndId($arg1, $arg2)
    {
        $this->iResetFromProjects($arg2);

        \Approve\Projects\Project::create(
            ['id' => $arg2, 'name' => $arg1]
        );
        //@TODO sqlite and TestDummy issue
        //https://laracasts.com/discuss/channels/general-discussion/testdummy-and-codeception-with-sqlite-in-memory-error-integrity-constraint-19
        //Factory::create('Approve\Projects\Project',
        //    ['id' => $arg2, 'name' => $arg1]);
    }
1 like

Please or to participate in this conversation.