The issue is that your test contains implicit commits and so ends the active transaction.
Re -
"As soon as I do a CREATE statement I get the transaction error." -
CREATE TABLE
etc are statements that cause an implicit commit.
This in turn means theRefreshDatabase
trait will not work because a rollback is not possible when the transaction is closed.
HencePDOException: There is no active transaction
It seems to be a known issue/thrown error with php 8.0 - https://github.com/laravel/framework/issues/35380
I figured it out for the case I was having. I am using a library wich uses the migration logic to execute data migrations (hence the$this->artisan('migrate-data');
in my code).
When using theRefreshDatabase
trait, migrations are executed once and after that, a transaction is started. The migration logic does something with transactions, I think closing them afterwards, causing the error I was having.
The solution that worked for me, was to overwrite theRefreshDatabase
trait to execute the data migrations before starting the transaction:
<?php
namespace Tests;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\RefreshDatabaseState;
trait RefreshDatabaseWithData
{
use RefreshDatabase;
protected function refreshTestDatabase(): void
{
if (! RefreshDatabaseState::$migrated) {
$this->artisan('migrate:fresh', $this->migrateFreshUsing());
$this->artisan('migrate-data'); // << I added this line
$this->app[Kernel::class]->setArtisan(null);
RefreshDatabaseState::$migrated = true;
}
$this->beginDatabaseTransaction();
}
}
This is tested in Laravel 9 only, but I don't see why this wouldn't work on previous versions.
This is how I solved it:
Step 1: Extend Connection class and override transaction method:
use Illuminate\Database\Connection as DBConnection;
use Closure;
class Connection extends DBConnection
{
public function transaction(Closure $callback, $attempts = 1)
{
$callback($this);
}
}
This override basically disables transactions internally, keeping your current code intact.
Step 2: Bind that concrete class to the abstract ConnectionInterface via a ServiceProvider (app/Providers/AppServiceProvider.php would be a good place):
if(config('app.env')==='testing') {
$this->app->bind(ConnectionInterface::class, Connection::class);
}
Notice that the binding is inside a condition against the environment. We want to apply this binding only when running tests.
If you're not using a .env.testing file for Unit Testing, I really recommend you to do it. It keeps everything much more cleaner. You can just copy .env to .env.testing and only update the DB_CONNECTION and DB_DATABASE constants, pointing to your test database.
Then define the .env.testing environment in phpinit.xml:
<php>
<env name="APP_ENV" value="testing"/>
<!-- <env name="DB_CONNECTION" value="memory_testing"/> -->
<!-- <env name="DB_DATABASE" value=":memory:"/> -->
</php>
Notice that I commented out DB_CONNECTION AND DB_DATABASE since those parameters will be fetched from .env.testing
Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Find the answer in similar questions on our website.
Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.
PHP (from the English Hypertext Preprocessor - hypertext preprocessor) is a scripting programming language for developing web applications. Supported by most hosting providers, it is one of the most popular tools for creating dynamic websites.
The PHP scripting language has gained wide popularity due to its processing speed, simplicity, cross-platform, functionality and distribution of source codes under its own license.
https://www.php.net/
Laravel is a free open source PHP framework that came out in 2011. Since then, it has been able to become the framework of choice for web developers. One of the main reasons for this is that Laravel makes it easier, faster, and safer to develop complex web applications than any other framework.
https://laravel.com/
Foundation, similar to Bootstrap, has become very popular as a more complex framework with some advanced but easy-to-implement CSS components. It is built with Sass, so just like Bootstrap, it is customizable. In addition to this, it also boasts some features that help make the design mobile responsive.
https://get.foundation/
Welcome to the Q&A site for web developers. Here you can ask a question about the problem you are facing and get answers from other experts. We have created a user-friendly interface so that you can quickly and free of charge ask a question about a web programming problem. We also invite other experts to join our community and help other members who ask questions. In addition, you can use our search for questions with a solution.
Ask about the real problem you are facing. Describe in detail what you are doing and what you want to achieve.
Our goal is to create a strong community in which everyone will support each other. If you find a question and know the answer to it, help others with your knowledge.