Summer Sale! All accounts are 50% off this week.

dima23's avatar

Call to a member function connection() on null when testing

Hello everyone,

Here's my setup: Laravel v8.83 with Sail v1.15.0 and PHPUnit v9.5.21. IDE: PhpStorm where test/php configurations are set to the remote interpreter, So I'm using Sail's PHP/PHPUnit versions and etc.

I'm trying to test registration, which requires data from the DB.

Let's take an example of the Grade model I have:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Grade extends Model
{
    use HasFactory;

    protected $fillable = ['label'];

    public function users(): HasMany
    {
        return $this->hasMany(User::class);
    }
}

Related factory:

namespace Database\Factories;

use App\Models\Grade;
use Faker\Provider\Lorem;
use Illuminate\Database\Eloquent\Factories\Factory;

class GradeFactory extends Factory
{
    protected $model = Grade::class;

    public function definition(): array
    {
        $this->faker->addProvider(new Lorem($this->faker));
        return [
            'label' => $this->faker->word,
            'active' => random_int(0, 1),
            'order' => $this->faker->randomNumber(),
            'created_at' => now(),
            'updated_at' => now(),
        ];
    }
}

My phpunit.xml:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true"
>
    <testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>
        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>
    </testsuites>
    <coverage processUncoveredFiles="true">
        <include>
            <directory suffix=".php">./app</directory>
        </include>
    </coverage>
    <php>
        <server name="APP_ENV" value="testing"/>
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <server name="DB_CONNECTION" value="sqlite"/>
        <server name="DB_DATABASE" value=":memory:"/>
        <server name="MAIL_MAILER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <server name="TELESCOPE_ENABLED" value="false"/>
    </php>
</phpunit>

And RegistrationTest:

<?php

namespace Tests\Feature;

use App\Models\Grade;
use Tests\TestCase;

class RegistrationTest extends TestCase
{
    protected function setUp(): void
    {
        Grade::factory()->count(3)->make();

        parent::setUp();
    }

    /** @test */
    public function user_can_see_registration_page()
    {
        $response = $this->get('/registration');

        $response->assertStatus(200);
    }
}

I'm getting Error : Call to a member function connection() on null error:

[docker://sail-8.0/app:latest/]:php /opt/project/vendor/phpunit/phpunit/phpunit --configuration /opt/project/phpunit.xml --filter "/(Tests\Feature\RegistrationTest::user_can_see_registration_page)( .*)?$/" --test-suffix RegistrationTest.php /opt/project/tests/Feature --teamcity
Testing started at 13:45 ...
PHPUnit 9.5.21 #StandWithUkraine


Error : Call to a member function connection() on null
 /opt/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:1653
 /opt/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:1619
 /opt/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php:1401
 /opt/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php:1347
 /opt/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php:919
 /opt/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:431
 /opt/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:212
 /opt/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Factories/Factory.php:678
 /opt/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Factories/Factory.php:387
 /opt/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php:157
 /opt/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Factories/Factory.php:392
 /opt/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Factories/Factory.php:370
 /opt/project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Factories/Factory.php:371
 /opt/project/tests/Feature/RegistrationTest.php:18

The same is when running the sail test command:

• Tests\Feature\Auth\RegistrationTest > user can see registration page
   Error 

  Call to a member function connection() on null

  at vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:1653
    1649▕      * @return \Illuminate\Database\Connection
    1650▕      */
    1651▕     public static function resolveConnection($connection = null)
    1652▕     {
  ➜ 1653▕         return static::$resolver->connection($connection);
    1654▕     }
    1655▕ 
    1656▕     /**
    1657▕      * Get the connection resolver instance.

      +11 vendor frames 

What am I doing wrong here? I was searching the whole internet and everywhere I see suggestions to replace PHPUnit\Framework\TestCase with Tests\TestCase which I'm already using. I'm already researching this for two days.

0 likes
6 replies
Sinnbeck's avatar

These need to be flipped in order. First you set up the app (database connection etc) and then you can seed

parent::setUp(); 
Grade::factory()->count(3)->make();
1 like
dima23's avatar

@Sinnbeck Ah didn't notice this. I've flipped this part and now I get General error: 1 no such table: grades (SQL: select * from "grades" where "active" = 1 order by "order" asc)

I think this is because of this part in routes/web.php:

    Route::statamic('user/registration', 'auth/register', [
        'title' => 'რეგისტრაცია',
        'grades' => Grade::whereActive(true)->orderBy('order')->get(),
        // ...
    ]);

Can I somehow setUp() the test before routes?

Sinnbeck's avatar
Sinnbeck
Best Answer
Level 102

@dima23 oh so that query is run on every single request no matter if you need that route? I have never used statamic, but can it use a closure?

'grades' => function () {
    return Grade::whereActive(true)->orderBy('order')->get();
},
1 like
dima23's avatar

@Sinnbeck Really? At least the debugbar wasn't showing queries on other pages...

I've added closure to that query and now it seems to work. Many thanks for helping.

Sinnbeck's avatar

@dima23 I would assume it does as it reads the route list every time to find the right one. But awesome that it's working. Be sure to test the route manually also

dima23's avatar

@Sinnbeck Yeah, thanks again.

Will try to find a way to refactor this code.

Please or to participate in this conversation.