Hi Guys, I have the following error using Pest on a fresh installation of Laravel & Nova:
Call to a member function connection() on null at vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:1342
I'm trying to test a custom validation rule which uses the database.
Directory structure:
app/
domains/
Systeem/
Rules/
User/
MinimaalEenAdmin.php
tests/
Unit/
Rules/
User/
MinimaalEenAdminTest.php
My Test:
<?php
use Domains\Systeem\Rules\User\MinimaalEenAdmin;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
test('een gebruiker beheerder maken kan altijd', function () {
$rule = new MinimaalEenAdmin();
assertTrue($rule->passes('admin', true));
});
test('een gebruiker geen beheerder maken zonder beheerders kan niet', function () {
$rule = new MinimaalEenAdmin();
assertFalse($rule->passes('admin', false));
});
My custom validation rule:
<?php
namespace Domains\Systeem\Rules\User;
use Domains\Systeem\User;
use Illuminate\Contracts\Validation\Rule;
class MinimaalEenAdmin implements Rule
{
private $resourceId;
public function __construct($resourceId = null)
{
$this->resourceId = $resourceId;
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
*
* @return bool
*/
public function passes($attribute, $value): bool
{
if ($value === '1') {
return true;
}
return User::query()
->where('admin', '=', true)
->when($this->resourceId, static function ($query, $resourceId) {
$query->where('id', '!=', $resourceId);
})
->exists();
}
public function message(): string
{
return __('systeem::validation.minimaal-een-admin');
}
}
composer.json:
"require": {
"php": "^7.4.1",
"fideloper/proxy": "^4.3.0",
"fruitcake/laravel-cors": "^1.0.6",
"guzzlehttp/guzzle": "^6.5.4",
"laravel/framework": "^7.14.1",
"laravel/nova": "^3.6.0",
"laravel/tinker": "^2.4.0"
},
"require-dev": {
"facade/ignition": "^2.0.6",
"fzaninotto/faker": "^1.9.1",
"mockery/mockery": "^1.4.0",
"nunomaduro/collision": "^5.0",
"pestphp/pest": "^0.1.5",
"phpunit/phpunit": "^9.2.1"
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
},
My phpunix.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>
<directory suffix="Test.php">./domains/Systeem/tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
<directory suffix="Test.php">./domains/Systeem/tests/Feature</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app</directory>
<directory suffix=".php">./domains</directory>
</whitelist>
</filter>
<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>
This test works fine:
<?php
use Domains\Systeem\Rules\User\MinimaalEenAdmin;
use Domains\Systeem\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
class MinimaalEenAdminTest extends \Tests\TestCase
{
use RefreshDatabase;
/** @test */
function een_gebruiker_beheerder_maken_kan_altijd()
{
$rule = new MinimaalEenAdmin();
$this->assertTrue($rule->passes('admin', '1'));
}
/** @test */
function een_gebruiker_geen_beheerder_maken_zonder_beheerders_kan_niet()
{
$rule = new MinimaalEenAdmin();
$this->assertFalse($rule->passes('admin', false));
}
}
Can I see your Pest.php file?
Hi @nunomaduro,
Here it is:
<?php
uses(Tests\TestCase::class)->in('Feature');
Also tried removing ->in('Feature'); but that didn't work either.
The funny thing is when I place de pest tests under the normal phpunit tests I get a different error:
Unable to locate factory for [Domains\Systeem\User].
or
Target class [config] does not exist.
When I remove the phpunit tests I got the connection error back. It looks like Laravel is not booted properly or something.
Running only the phpunit style tests works with ./vendor/bin/pest but when I add --coverage the following error is given: Undefined variable: factory at domains/Systeem/database/factories/UserFactory.php:20
Using uses(Tests\TestCase::class)->in('Feature', 'Unit'); will fixed your problem.
@nunomaduro the Call to a member function connection on null is gone but now I got 2 new errors:
Illuminate\Contracts\Container\BindingResolutionException
Target class [config] does not exist.
at vendor/laravel/framework/src/Illuminate/Container/Container.php:807
and
Unable to locate factory for [Domains\Systeem\User].
at vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:273
The --coverage still gives the Undefined variable: factory at domains/Systeem/database/factories/UserFactory.php:20 even with the uses(Tests\TestCase::class)->in('Feature', 'Unit');
Using ./vender/bin/phpunit works fine.
@cliffordjames All the folders that use Laravel someway need to be listed on the in method: uses(Tests\TestCase::class)->in('Feature', 'Unit');
@nunomaduro Thanks, that works:
<?php
uses(Tests\TestCase::class)->in(
'Feature',
'Unit',
'../domains/Systeem/tests/Unit',
);
The only problem that still exists is the one with --coverage
./vendor/bin/pest --coverage
Whoops\Exception\ErrorException
Undefined variable: factory
at domains/Systeem/database/factories/UserFactory.php:20
Does your factory file have a PHPDoc tag at the top like this?
/** @var \Illuminate\Database\Eloquent\Factory $factory */
It might just be because it can't work out where the $factory instance is coming from when doing the coverage.
@owenvoke yes the factory file starts with:
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
...
Ah, ok. That's interesting that it's failing to find the variable. 馃え
@cliffordjames
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app</directory>
<directory suffix=".php">./domains</directory>
</whitelist>
The user factories/UserFactory.php file can not be processed by coverage.
Thanks, this fixed the problem:
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app</directory>
<directory suffix=".php">./domains</directory>
<exclude>
<directory>./domains/*/database</directory>
</exclude>
</whitelist>
</filter>
Most helpful comment
Thanks, this fixed the problem: