itsjoshbruce's avatar

Laravel 5.8 Testing w/ Database Must Run One at a Time

Odd behavior that could be coming from the not doing it correctly place. I'm also not sure what all information would help keep this succinct yet cover the issue - updates will be added ass necessary.

Consider a vanilla Laravel install.

// UserTest.php

class UserTest extends TestCase
{
    use RefreshDatabase;

    public function testOne()
    {
        $user = User::make(['email' => '[email protected]']);
        $user->save();
        $this->assertTrue($user->id == 1);
    }

    public function testTwo()
    {
        $user = User::make(['email' => '[email protected]']);
        $user->save();
        $this->assertTrue($user->id == 1);
    }
}

Running the tests one at a time, they both pass (phpunit --filter=testOne and phpunit --filter=testTwo). Run them sequentially, all but the first will error out with a timeout error (phpunit).

What's going on (I'd really like to understand the why)? And what's the fix?

What I've tried:

  1. Use in-memory SQLite.
  2. Use DatabaseTransactions instead of DatabaseRefresh

Would like to be as close to production-like as possible.

0 likes
2 replies
bobbybouwmann's avatar

What happens when you run phpunit tests/Unit/UserTest.php?

The problem might be in another test right? If you run phpunit it will run all tests of your application.

itsjoshbruce's avatar

Good question. Just to make sure, the tests above are samples, not actuals - just don't want to get bogged down in specific implementations unless it is literally the problem, which I don't think it is...?? Also, this is Laravel 5.8.

Anyhow.

I have a real test file with three tests requiring DB connections: tests/Unit/PersonaTest.php - it uses the RefreshDatabase trait.

When all three tests are run:

  1. Fails because it's the one I'm currently working on.
  2. Timeout.
  3. Timeout.

When run individually:

  1. Fails (error) - undefined method
  2. Fails (no error) - retrieving username, which is blank
  3. Fails (error) - undefined method

tests/Unit/UserTest.php - has 3 tests as well.

  1. Passes.
  2. Timeout.
  3. Timeout.

When run individually:

  1. Passes.
  2. Passes.
  3. Passes.

tests/Unit/InvitationTest.php - has 6 tests, none require DB connection.

  1. Passes.
  2. Passes.
  3. Passes.
  4. Passes.
  5. Passes.
  6. Passes.

When run individually - all pass

tests/Unit/CharonTest.php - has 7 tests, none require DB connection.

All pass.

When run individually - all pass.

This is why I'm thinking it's directly tied to the DB connection concept. Let's try a suite that only has one test that requires a DB connection, to be thorough.

I will comment out all but one from tests/Unit/UserTest.php.

  1. Passes.

When run individually - passes.

I've actually created a phpunit group to exclude those tests when I run just phpunit. Of course, this causes problems when I actually do break something, hence why I'm asking for help.

From what I'm seeing online, it has to do with speed and asynchronous behavior.

Like a test is trying to build the DB while the previous one is still tearing it down or something. Hence the recommendations for in-memory and sqlite. I've also read about differences between sqlite and mysql that make me want to be as close to production as possible. I've also read about increasing the timeout in general...none of this last bit has been tested or verified by me.

I'm hoping for a solution and not a workaround that becomes the solution. This may be something that I'm causing or it may be a defect that hasn't been captured because many of us accept workarounds when we find them. All I know is I don't know what's going on and it might be close enough to the metal that it's beyond my depth. (I work from the human to the metal, not the other way around.)

Anyway, confused and curious.

Please or to participate in this conversation.