When testing database laravel's documentation suggest using RefreshDatabase trait.
But that cause Error: Call to a member function beginTransaction() on null
Did you fixed it? @theminer3746
Would love to know if some of you achieved a solution...
@lscarneiro I created a trait that resets the db
<?php
namespace Tests;
use DB;
use Jenssegers\Mongodb\Schema\Blueprint;
trait RefreshDatabase
{
/**
* Set up function.
*/
public function setUp(): void
{
parent::setUp();
if ($this->hasDependencies()) {
return;
}
$this->dropAllCollections();
}
/**
* Drop all collections.
*/
protected function dropAllCollections(): void
{
$mongo = DB::connection('mongodb');
foreach ($mongo->listCollections() as $collection) {
if (starts_with($name = (string) $collection->getName(), 'system')) {
continue;
}
(new Blueprint($mongo, $name))->drop();
}
}
}
Thanks @LucasLeandro1204.
I wanted a more "generic" approach, so what I did was create a Trait in app\Traits (new folder in my case) with:
<?php
namespace App\Traits;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Foundation\Testing\RefreshDatabaseState;
trait RefreshDatabaseTransactionLess
{
/**
* Refresh a conventional test database.
*
* @return void
*/
public function refreshTestDatabase()
{
if (!RefreshDatabaseState::$migrated) {
$this->artisan('migrate:fresh', $this->shouldDropViews() ? [
'--drop-views' => true,
] : []);
$this->app[Kernel::class]->setArtisan(null);
RefreshDatabaseState::$migrated = true;
}
}
}
And in my test class I use both RefreshDatabase and RefreshDatabaseTransactionLess this way:
use RefreshDatabase, RefreshDatabaseTransactionless {
RefreshDatabaseTransactionless::refreshTestDatabase insteadof RefreshDatabase;
}
That tip I got from this StackOverflow post
I consider it a Hack, because it does not solve the original problem, which is execute transactions with this MongoDB Laravel driver.
The code from refreshTestDatabase() inside RefreshDatabaseTransactionLess didn't come out of thin air, it's actually the same code from the original trait, but skipping the call to $this->beginDatabaseTransaction();
Just thinking a little further.
An even cleaner approach is to instead of overriding refreshTestDatabase(), to actually override beginDatabaseTransaction().
Just tested here and it works like a charm!
in RefreshDatabaseTransactionLess trait
<?php
namespace App\Traits;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Foundation\Testing\RefreshDatabaseState;
trait RefreshDatabaseTransactionLess
{
/**
* Begin a database transaction on the testing database.
*
* @return void
*/
public function beginDatabaseTransaction()
{
// Nothing! This is on purpose! just skip me!
}
}
And on the test class:
use RefreshDatabase, RefreshDatabaseTransactionless {
RefreshDatabaseTransactionless::beginDatabaseTransaction insteadof RefreshDatabase;
}
That way we're achieving the exact "hack" that we want, skip the transaction part (that breaks the test).
I created this Gist containing an example of implementation of the Hack
Just discovered that in my case, using use DatabaseMigrations; trait, solves my actual problem (reset database after each test) with just one line.
@lscarneiro , how to override beginTransaction() method?
@prashant-pokhriyal sorry for the delay.
If you're talking about the specific $connection->beginTransaction(); on RefreshDatabase trait, I would say that this is not the easiest approach because it is a method from a yet another class.
Which behavior are you targetting specifically?
@lscarneiro Actually I'm using a library which internally uses Transactions. Since laravel-mongodb does not have Transaction, it throws an error: Call to a member function beginTransaction() on null. I somehow want to bypass this.
I don't think I have a solution for your case, maybe you could try some help with the library issues page, here in my case I didn't change laravel-mongodb code itself, but rather the code that "depends" on transactions per se.
Any news on this?
Most helpful comment
Just discovered that in my case, using
use DatabaseMigrations;trait, solves my actual problem (reset database after each test) with just one line.