本文目录导读:

在Laravel中进行数据库测试时,事务回滚是一种确保测试数据不会污染实际数据库的常用方法,以下是详细的实现方案:
基础设置
使用RefreshDatabase Trait(推荐)
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class UserTest extends TestCase
{
use RefreshDatabase;
public function test_create_user()
{
$response = $this->post('/users', [
'name' => 'John Doe',
'email' => 'john@example.com',
'password' => 'password123'
]);
$response->assertStatus(201);
$this->assertDatabaseHas('users', [
'email' => 'john@example.com'
]);
}
}
使用DatabaseTransactions Trait(轻量级)
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
class UserTest extends TestCase
{
use DatabaseTransactions;
public function test_update_user()
{
$user = User::factory()->create();
$response = $this->put("/users/{$user->id}", [
'name' => 'Updated Name'
]);
$response->assertStatus(200);
$this->assertDatabaseHas('users', [
'id' => $user->id,
'name' => 'Updated Name'
]);
}
}
配置测试数据库
.env.testing 文件
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel_test DB_USERNAME=root DB_PASSWORD=
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>
<php>
<env name="APP_ENV" value="testing"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="MAIL_MAILER" value="array"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="TELESCOPE_ENABLED" value="false"/>
</php>
</phpunit>
高级用法
手动事务控制
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Support\Facades\DB;
class AdvancedTest extends BaseTestCase
{
public function test_with_manual_transaction()
{
DB::beginTransaction();
try {
// 测试代码
$user = User::create([
'name' => 'Test User',
'email' => 'test@example.com',
'password' => bcrypt('password')
]);
$this->assertNotNull($user->id);
// 在事务内验证
$this->assertEquals(1, DB::table('users')->count());
DB::rollBack();
} catch (\Exception $e) {
DB::rollBack();
throw $e;
}
// 回滚后验证
$this->assertEquals(0, DB::table('users')->count());
}
}
跨多个数据库的事务处理
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class MultiDatabaseTest extends TestCase
{
use DatabaseTransactions;
protected $connectionsToTransact = ['mysql', 'mysql_secondary'];
public function test_multi_database_operation()
{
DB::connection('mysql')->table('users')->insert([
'name' => 'User 1',
'email' => 'user1@example.com'
]);
DB::connection('mysql_secondary')->table('logs')->insert([
'message' => 'User created',
'user_id' => 1
]);
// 事务结束后,两个数据库的更改都会被回滚
}
}
性能优化
使用连接池(MySQL)
// config/database.php
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'pool' => [
'max' => 10,
'min' => 2,
],
],
测试数据工厂优化
// database/factories/UserFactory.php
$factory->define(User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => bcrypt('password'),
'remember_token' => Str::random(10),
];
});
常见问题和解决方案
问题1:内存数据库(SQLite)不生效
// 确保 SQLite 扩展已启用 // 检查 php.ini 中的 pdo_sqlite 扩展
问题2:外键约束导致的事务失败
// 在测试基类中禁用外键约束
class TestCase extends BaseTestCase
{
use CreatesApplication;
protected function setUp(): void
{
parent::setUp();
if (DB::connection()->getDriverName() === 'mysql') {
DB::statement('SET FOREIGN_KEY_CHECKS = 0');
}
}
protected function tearDown(): void
{
if (DB::connection()->getDriverName() === 'mysql') {
DB::statement('SET FOREIGN_KEY_CHECKS = 1');
}
parent::tearDown();
}
}
问题3:测试并行执行时的冲突
// parallel testing 配置(需要安装 paratest) // composer require brianium/paratest // vendor/bin/paratest --processes 8
最佳实践
选择合适的事务策略
// 适用于简单测试
use DatabaseTransactions;
// 适用于需要重置所有数据的测试
use RefreshDatabase;
// 适用于大型测试套件(混合使用)
class UserTest extends TestCase
{
use DatabaseTransactions; // 快速回滚
public function test_complex_scenario()
{
// 使用 RefreshDatabase 风格的重置
$this->refreshDatabase();
// 测试代码
}
}
测试辅助方法
// tests/TestCase.php
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
protected function setUp(): void
{
parent::setUp();
// 设置测试环境
config(['app.debug' => true]);
}
protected function tearDown(): void
{
$this->flushSession();
parent::tearDown();
}
}
监控和调试
查看执行的SQL语句
// 在测试中启用 SQL 日志
DB::enableQueryLog();
$this->post('/users', [...]);
dump(DB::getQueryLog());
通过合理使用事务回滚机制,可以确保测试的隔离性、可靠性和性能,选择合适的Trait和配置,可以让你的测试套件既高效又稳定。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播