10

I'm writing tests for my Laravel application using the Codeception library. I'm using the Laravel5 module, and have it configured with cleanup which means that all tests will run inside a database transaction, so that my testing database doesn't get filled with test data.

One of the endpoints I'm testing has the following validation rules set against it via Form Requests:

public function rules()
{
    return ['user_id' => 'required|exists:users,id'];
}

The test that I've written to POST to this endpoint is as follows:

public function store(ApiTester $I)
{
    // Create a couple of users
    $users = factory(\App\Models\User::class, 2)->create();

    $I->wantTo('ask someone to be my friend');
    $I->authenticateAs($users[0]);
    $I->sendPOST('users/' . $users[0]->id . '/friendships', [
        'user_id' => $users[1]->id
    ]);
    $I->seeResponseCodeIs(201);
}

This test always fails. After investigating, I can see that it fails because the request is failing validation due to the exists:users,id rule. If I change the Codeception settings to not execute tests inside a transaction, Laravel's validator can successfully see the existence of the two user's that I created at the start of my test and the test passes.

So, my question is, is there any way that I can maintain the behaviour of wrapping each of my tests in a database transaction, and have Laravel's validator be able to see the records that I create in my tests?

John Dorean
  • 3,744
  • 9
  • 51
  • 82

2 Answers2

4

The problem is, that if the transaction is not commited, the original data in the database tables is not affected. So within the transaction, you create two users, but there is no commit statement that would persist that to your database. Hence the laravel validation rule 'exists' cannot find them ( that rule makes a database request to find particular user_id ).

So in your case the users have to exist before testing. I would recommend to use Migrations instead. Resetting Database after each test

Create your tables with database migrations and seeds and roll them back after tests have finished.

shock_gone_wild
  • 6,700
  • 4
  • 28
  • 52
  • I was hoping to be able to avoid migrating my database before every test. It seems like that would have a high performance penalty compared with executing inside a transaction. What I don't really understand is how Laravel's validator can't see the users that I created, are Laravel and Codeception using two different database connections? – John Dorean Oct 22 '15 at 15:16
0

Quote:

$I->sendPOST('users/' . $users[0]->id . '/friendships', [
    'user_id' => $users[1]->id
]);

Why are you sending $users[0]->id in the request url and then 'user_id' => $users[1]->id in the parameters?

Could this be your problem? Could this be the reason you are failing the validation?

Jamesking56
  • 3,683
  • 5
  • 30
  • 61
  • This isn't the problem. This endpoint accepts the user ID of *another* user which you're asking to be friends with. – John Dorean Oct 17 '15 at 21:57