Reputation: 1416
I have a Laravel project running version 5.6. The connected database is mongodb with the jenssegers/mongodb package.
I wrote a single Unittest to test a function related to the User.
The test creates new users in a configured test mongodb database.
I want to refresh the database after each test run so I use the RefreshDatabase
Trait.
When using the RefreshDatabase
Trait I get the following error when running my test:
There was 1 error:
1) Tests\Unit\UserTest::it_gets_top_user Error: Call to a member function beginTransaction() on null
When not using the Trait the test creates all the necessary stuff in the database and performs the assertion without an error.
The test looks like this:
/** @test */
public function it_gets_top_user()
{
factory(\App\Users\User::class, 5)->create();
$userOne = factory(\App\Users\User::class)->create([
'growth' => 10
]);
$topUser = Users::getTopUser();
$collection = new Collection();
$collection->push($userOne);
$this->assertEquals($collection, $topUser);
}
I use the following versions in my composer.json:
"laravel/framework": "5.6.*",
"jenssegers/mongodb": "3.4.*",
"phpunit/phpunit": "~7.0",
The following versions are used on the server:
I call the test with the phpunit installed in the vendor directory with:
vendor/phpunit/phpunit/phpunit
Upvotes: 3
Views: 2907
Reputation: 1416
The problem seems to be, that the RefreshDatabase
Trait does not work at all for a MongoDB environment.
I solved the above problem by creating my own RefreshDatabase
Trait in the testing/
directory of my Laravel project.
The Trait looks like this:
<?php
namespace Tests;
trait RefreshDatabase
{
/**
* Define hooks to migrate the database before and after each test.
*
* @return void
*/
public function refreshDatabase()
{
$this->dropAllCollections();
}
/**
* Drop all collections of the testing database.
*
* @return void
*/
public function dropAllCollections()
{
$database = $this->app->make('db');
$this->beforeApplicationDestroyed(function () use ($database) {
// list all collections here
$database->dropCollection('users');
});
}
}
To enable this Trait I have overridden the setUpTraits
function in the TestCase
Class. It now looks like this:
/**
* Boot the testing helper traits.
*
* @return array
*/
protected function setUpTraits()
{
$uses = array_flip(class_uses_recursive(static::class));
if (isset($uses[\Tests\RefreshDatabase::class])) {
$this->refreshDatabase();
}
if (isset($uses[DatabaseMigrations::class])) {
$this->runDatabaseMigrations();
}
if (isset($uses[DatabaseTransactions::class])) {
$this->beginDatabaseTransaction();
}
if (isset($uses[WithoutMiddleware::class])) {
$this->disableMiddlewareForAllTests();
}
if (isset($uses[WithoutEvents::class])) {
$this->disableEventsForAllTests();
}
if (isset($uses[WithFaker::class])) {
$this->setUpFaker();
}
return $uses;
}
And finally in all my testing classes I can use my newly created Trait like this:
<?php
namespace Tests\Unit;
use Illuminate\Database\Eloquent\Collection;
use Tests\RefreshDatabase;
use Tests\TestCase;
class UserTest extends TestCase
{
use RefreshDatabase;
// tests happen here
}
Upvotes: 6