本文目录导读:

- 使用 PHPUnit 数据库扩展(推荐)
- 使用 PHPUnit + PDO 直接断言
- 使用 Doctrine DBAL 和 Schema 断言
- 自定义断言辅助方法
- 使用 Laravel 的测试方法(如果是 Laravel 项目)
- 最佳实践建议
在 PHP 中进行数据库断言主要有以下几种方式和工具:
使用 PHPUnit 数据库扩展(推荐)
安装
composer require --dev phpunit/dbunit
基本用法
<?php
use PHPUnit\Framework\TestCase;
use PHPUnit\DbUnit\TestCaseTrait;
class UserDaoTest extends TestCase
{
use TestCaseTrait;
private static $pdo;
// 数据库连接配置
public function getConnection()
{
if (self::$pdo == null) {
self::$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', 'password');
}
return $this->createDefaultDBConnection(self::$pdo, 'test');
}
// 测试数据
public function getDataSet()
{
return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/users.xml');
}
public function testUserExists()
{
// 执行数据库操作
$dao = new UserDao();
$dao->createUser('John', 'john@example.com');
// 断言数据库中的记录
$queryTable = $this->getConnection()->createQueryTable(
'users',
'SELECT * FROM users WHERE email = "john@example.com"'
);
// 构建期望数据
$expectedTable = $this->createArrayDataSet([
'users' => [
['id' => 1, 'name' => 'John', 'email' => 'john@example.com'],
]
])->getTable('users');
$this->assertTablesEqual($expectedTable, $queryTable);
}
public function testRowCount()
{
$dao = new UserDao();
$dao->deleteUser(1);
$this->assertEquals(2, $this->getConnection()->getRowCount('users'));
}
}
使用 PHPUnit + PDO 直接断言
<?php
use PHPUnit\Framework\TestCase;
class DatabaseAssertionsTest extends TestCase
{
private $pdo;
protected function setUp(): void
{
$this->pdo = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
public function testDatabaseContainsRecord()
{
// 执行测试操作
$stmt = $this->pdo->prepare('INSERT INTO products (name, price) VALUES (?, ?)');
$stmt->execute(['Test Product', 19.99]);
// 断言记录存在
$stmt = $this->pdo->prepare('SELECT COUNT(*) FROM products WHERE name = ?');
$stmt->execute(['Test Product']);
$count = $stmt->fetchColumn();
$this->assertEquals(1, $count, '记录应该已插入到数据库');
}
public function testSpecificValues()
{
$productId = 1;
$stmt = $this->pdo->prepare('SELECT * FROM products WHERE id = ?');
$stmt->execute([$productId]);
$product = $stmt->fetch(PDO::FETCH_ASSOC);
// 断言具体字段值
$this->assertEquals(19.99, $product['price']);
$this->assertEquals('Test Product', $product['name']);
$this->assertNotNull($product['created_at']);
}
public function testRecordDoesNotExist()
{
$productId = 999; // 不存在的ID
$stmt = $this->pdo->prepare('SELECT COUNT(*) FROM products WHERE id = ?');
$stmt->execute([$productId]);
$count = $stmt->fetchColumn();
$this->assertEquals(0, $count, '记录不应该存在');
}
}
使用 Doctrine DBAL 和 Schema 断言
<?php
use Doctrine\DBAL\DriverManager;
use PHPUnit\Framework\TestCase;
class SchemaAssertionsTest extends TestCase
{
private $conn;
protected function setUp(): void
{
$this->conn = DriverManager::getConnection([
'driver' => 'pdo_mysql',
'host' => 'localhost',
'dbname' => 'test',
'user' => 'root',
'password' => 'password',
]);
}
public function testTableExists()
{
$sm = $this->conn->getSchemaManager();
$this->assertTrue($sm->tablesExist(['users']), 'users表应该存在');
}
public function testColumnExists()
{
$sm = $this->conn->getSchemaManager();
$columns = $sm->listTableColumns('users');
$this->assertArrayHasKey('id', $columns);
$this->assertArrayHasKey('name', $columns);
$this->assertArrayHasKey('email', $columns);
}
public function testColumnType()
{
$sm = $this->conn->getSchemaManager();
$column = $sm->listTableColumns('users')['price'];
$this->assertEquals('decimal', $column->getType()->getName());
}
}
自定义断言辅助方法
<?php
trait DatabaseAssertions
{
protected $pdo;
protected function assertTableContains($table, array $expectedRows, $message = '')
{
$sql = "SELECT * FROM {$table}";
$actualRows = $this->pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
foreach ($expectedRows as $expectedRow) {
$this->assertContains(
$expectedRow,
$actualRows,
$message ?: "Table {$table} should contain the expected row"
);
}
}
protected function assertRowCount($table, $expectedCount, $where = '', $message = '')
{
$sql = "SELECT COUNT(*) FROM {$table}";
if ($where) {
$sql .= " WHERE {$where}";
}
$actualCount = $this->pdo->query($sql)->fetchColumn();
$this->assertEquals(
$expectedCount,
(int)$actualCount,
$message ?: "Expected {$expectedCount} rows in {$table} but got {$actualCount}"
);
}
}
// 使用示例
class ProductTest extends TestCase
{
use DatabaseAssertions;
protected function setUp(): void
{
$this->pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
}
public function testProductTable()
{
$this->assertTableContains('products', [
['name' => 'Phone', 'price' => 599.99],
['name' => 'Laptop', 'price' => 999.99],
]);
$this->assertRowCount('products', 2, 'active = 1');
}
}
使用 Laravel 的测试方法(如果是 Laravel 项目)
<?php
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class UserTest extends TestCase
{
use RefreshDatabase;
public function testUserCanBeCreated()
{
$response = $this->post('/api/users', [
'name' => 'John Doe',
'email' => 'john@example.com',
]);
$this->assertDatabaseHas('users', [
'name' => 'John Doe',
'email' => 'john@example.com',
]);
$this->assertDatabaseCount('users', 1);
$this->assertDatabaseMissing('users', [
'email' => 'nonexistent@example.com',
]);
}
public function testDatabaseTransactions()
{
// 使用 create 方法
$user = User::factory()->create();
$this->assertDatabaseHas('users', [
'id' => $user->id,
'name' => $user->name,
]);
}
}
最佳实践建议
- 使用事务:在测试中开启事务,测试结束后回滚,避免数据污染
- 分离测试库:使用单独的测试数据库,避免影响生产数据
- 使用 Fixtures:准备固定的测试数据
- 断言明确:断言具体的数据值,而不是仅仅检查数量
- 测试隔离:每个测试相互独立,不依赖测试数据
// 使用事务隔离测试
class ProductTest extends TestCase
{
private $pdo;
protected function setUp(): void
{
$this->pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$this->pdo->beginTransaction();
}
protected function tearDown(): void
{
$this->pdo->rollBack();
}
public function testCreateProduct()
{
// 测试逻辑...
$this->pdo->exec("INSERT INTO products (name) VALUES ('Test')");
$count = $this->pdo->query("SELECT COUNT(*) FROM products")->fetchColumn();
$this->assertEquals(1, $count);
// 测试结束后自动回滚
}
}
选择哪种方式取决于:
- 项目是否使用框架(Laravel/Symfony)
- 测试框架类型(PHPUnit/Pest)
- 数据库类型(MySQL/PostgreSQL/SQLite)
- 对测试速度和复杂性的要求
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播