longestdrive's avatar

Laravel testing - using RefreshDatabase but table not found

Hi

I'm trying to refactor a class and having problems testing it when I place certain code in the __constructor method and it throws an error that table not found.

I know this means that in the testing environment the table has yet to be created and although I'm using RefreshDatabase within the test it appears that at the point the class I'm testing initialises and attempts to access the database it's not ready. So I'm either doing something in the constructor I shouldn't or I'm missing something in my test structure.

Here's the basics of the class I'm tryting to test:

class PlayerRounds
{

    use EclecticPresenter;

    private RoundRepository $roundRepository;

    private CourseRepository $courseRepository;

    private $courseHoles;

    public function __construct(RoundRepository $roundRepository, CourseRepository $courseRepository)
    {
        $this->roundRepository = $roundRepository;
        $this->courseRepository = $courseRepository;
        $this->init();

    }

  private function init()
    {
        $this->courseHoles = $this->courseRepository->all();
    }

    /**
     * generates eclecic rounds for each league the player is in
     * @param Player $player
     */
    public function getAllEclecticRounds(Player $player)
    {
        $allEclecticRounds = collect();

        $leagues = $player->league()->where('league_type', 'eclectic')->get();

        $leagues->each(function ($league) use ($player, $allEclecticRounds) {
            $newRound = $this->getPlayerEclecticRound($player, $league);
            $allEclecticRounds->put($league->id, $newRound);
        });

        return $allEclecticRounds;
    }

The test fails at the init() method. The fetch $this->courseHoles = $this->courseRepository->all(); the the database fails if it's within the constructor, It works if I place this piece of code within each method that needs it but means I call it often rather than once.

Here's my test:

class PlayerRoundsTest extends TestCase
{
    use RefreshDatabase;
    use EclecticTestHelper;
    use WithFaker;

    private $playerRounds;

    protected function setUp(): void
    {
        parent::setUp();

        $this->seed(CourseTableSeeder::class);

        $this->playerRounds = app()->make(PlayerRounds::class);
    }

    /**
     * @test
     * @covers PlayerRounds::getAllEclecticRounds
     * @description:
     */
    public function it_returns_an_eclectic_round_for_all_leagues()
    {
        $player = Player::factory()->has(League::factory()->count(3))->create();

        foreach ($player->league()->get() as $league) {
            for ($x = 0; $x <= 3; $x++) {
                $this->createScores($league, $player);
            }
        }

        $result = $this->playerRounds->getAllEclecticRounds($player);

        $this->assertCount(3, $result);
        $result->each(function($collection) {
            $this->assertCount(1, $collection);
        });

Are there any ideas how I can initiate the class correctly and get the test set up correct and ensure the database is ready for the test. I assumed using RefreshDatabase was the correct approach and I had things in the correct order.

Thank you

0 likes
1 reply
longestdrive's avatar

Ok, after a bit of playing around the error is being caused by the loading of a custom artisan command I created. That command class has a dependency of another class which in turn calls on the class I'm testing.

I removed the command from Kernel.php as follows:

protected $commands = [
        Inspire::class,
        FixtureReminder::class,
        SmsFixtureReminder::class,
        UpdateMigrationTable::class,
//        EclecticUpdate::class,
//        MatchplayUpdate::class,
        CleanTemporaryFiles::class,
        AuthPermissionCommand::class
    ];

So - am I right in assuming for test purposes this is going to be impossible to isolate without changing this each time? This all relates to dependencies and the order in which CreateApplication works but I don't know enough to work around this.

Please or to participate in this conversation.