PHP 测试:框架与工具
高质量的测试是可靠 Web 应用程序的基础。在 PHP 生态系统中,已经形成了一套强大的工具集,涵盖了从单元测试到验收测试的所有层级。本文将介绍主要的框架和库,帮助您编写干净、可测试的代码。
1. PHPUnit — 事实上的标准
PHPUnit 仍然是 PHP 中最流行的单元测试框架。它被包含在 Symfony、Laravel 以及许多其他项目中。主要功能:
- 支持断言 — 从简单的
assertEquals到复杂的assertJsonStructure。 - 用于准备和清理数据的 Fixtures(
setUp()、tearDown())。 - 生成 HTML、XML、Clover 格式的报告。
- 与 CI/CD 集成(GitHub Actions、GitLab CI、Jenkins)。
<?php
use PHPUnit\\Framework\\TestCase;
class CalculatorTest extends TestCase
{
public function testAddition()
{
$calc = new Calculator();
$this->assertEquals(4, $calc->add(2, 2));
}
public function testDivisionByZero()
{
$this->expectException(\\DivisionByZeroError::class);
$calc = new Calculator();
$calc->divide(10, 0);
}
}
2. Mockery — 灵活的模拟对象创建
Mockery 扩展了 PHPUnit 创建 mock 对象的能力。当需要替换复杂服务或数据库时,它非常方便。
- 支持部分模拟(partial mocks)。
- 检查方法调用顺序(
shouldReceive)。 - 处理魔术方法(
__call、__get)。
<?php
use Mockery as m;
class OrderProcessorTest extends TestCase
{
public function testProcess()
{
$gateway = m::mock(PaymentGateway::class);
$gateway->shouldReceive('charge')
->once()
->with(100.0)
->andReturn(true);
$processor = new OrderProcessor($gateway);
$this->assertTrue($processor->process(100.0));
}
protected function tearDown(): void
{
m::close();
}
}
3. Codeception — 一体化解决方案
Codeception 将单元测试、功能测试和验收测试统一在单一语法中。在需要测试表单、AJAX 请求和数据库的 Web 项目中尤其受欢迎。
- 用于操作 PHPBrowser、Selenium、Laravel、Symfony 的模块。
- 通过 CLI 生成测试:
codecept generate:test。 - 通过 Gherkin 支持 BDD(行为驱动开发)。
<?php
// acceptance.suite.yml
actor: AcceptanceTester
modules:
enabled:
- WebDriver:
url: 'http://localhost'
browser: chrome
- Laravel5:
environment_file: .env.testing
// tests/acceptance/LoginCept.php
$I = new AcceptanceTester($scenario);
$I->wantTo('see that login form works');
$I->amOnPage('/login');
$I->fillField('email', 'user@example.com');
$I->fillField('password', 'secret');
$I->click('Login');
$I->see('Dashboard');
4. Pest — 极简语法
Pest 是 PHPUnit 的现代替代品,具有受 JavaScript 库 Jest 启发的简洁语法。非常适合重视测试可读性的开发者。
- 自动依赖解析。
- 断言链:
expect($result)->toBeTrue()。 - 内置并行运行支持。
<?php
use function Pest\\Faker\\faker;
test('it creates a user', function () {
$user = User::factory()->create([
'name' => faker()->name,
'email' => faker()->email,
]);
expect($u