本文目录导读:

在 PHP 中进行单元测试,最主流的方案是使用 PHPUnit,下面是一个从零开始的完整指南,涵盖安装、编写、运行和最佳实践。
环境准备与安装
你需要确保系统安装了 Composer(PHP 的依赖管理工具)。
使用 Composer 安装 PHPUnit
在项目根目录打开终端,运行:
composer require --dev phpunit/phpunit
这会在 vendor/bin/ 目录下生成 phpunit 可执行文件。
编写第一个测试用例
第一步:准备被测试的类
在 src/ 目录下创建一个简单的计算器类:
<?php
// src/Calculator.php
namespace App;
class Calculator
{
public function add(int $a, int $b): int
{
return $a + $b;
}
public function divide(int $a, int $b): float
{
if ($b === 0) {
throw new \InvalidArgumentException("除数不能为零");
}
return $a / $b;
}
}
第二步:创建测试类
在 tests/ 目录下创建对应的测试文件(命名规范:类名Test.php):
<?php
// tests/CalculatorTest.php
namespace App\Tests;
use App\Calculator;
use PHPUnit\Framework\TestCase;
class CalculatorTest extends TestCase
{
private Calculator $calculator;
// 在每个测试方法运行前执行(初始化)
protected function setUp(): void
{
parent::setUp();
$this->calculator = new Calculator();
}
// 测试加法
public function testAdd(): void
{
$result = $this->calculator->add(5, 3);
$this->assertEquals(8, $result);
}
// 测试异常情况
public function testDivideByZeroThrowsException(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->calculator->divide(10, 0);
}
// 测试带数据提供器的用例(推荐)
#[DataProvider('additionProvider')]
public function testAddWithDataProvider(int $a, int $b, int $expected): void
{
$result = $this->calculator->add($a, $b);
$this->assertEquals($expected, $result);
}
// 数据提供器:提供多组测试数据
public static function additionProvider(): array
{
return [
[1, 2, 3],
[10, -5, 5],
[-3, -7, -10],
[100, 250, 350]
];
}
}
运行测试
运行全部测试
./vendor/bin/phpunit
运行特定文件
./vendor/bin/phpunit tests/CalculatorTest.php
运行特定方法
./vendor/bin/phpunit --filter testAdd tests/CalculatorTest.php
输出测试覆盖率
./vendor/bin/phpunit --coverage-text
注意:需要安装 Xdebug 或 PCOV 扩展才能查看覆盖率。
核心断言方法(常用)
| 断言方法 | |
|---|---|
assertEquals |
值相等(宽松比较) |
assertSame |
值相等且类型一致(严格比较) |
assertTrue / assertFalse |
布尔值验证 |
assertNull |
是否为 null |
assertInstanceOf |
对象类型 |
assertCount |
数组元素个数 |
assertStringContainsString |
字符串包含某子串 |
expectException |
预期抛出异常 |
高级特性与最佳实践
1 测试隔离
每次测试运行前,PHPUnit 都会重新创建测试类实例,但如果有依赖外部资源(如数据库、文件),需要确保测试之间互不影响。
2 模拟对象(Mock)
用于测试依赖外部服务的类,测试一个发送短信的服务:
$smsService = $this->createMock(SmsService::class);
$smsService->expects($this->once())
->method('send')
->with($this->stringContains('验证码'))
->willReturn(true);
$orderService = new OrderService($smsService);
$orderService->placeOrder(); // 内部会调用短信服务
3 测试数据库(示例)
对于需要数据库的测试,通常使用 SQLite 内存数据库或 Mock 数据库层。
4 常用注解(Attributes)
#[Test]:显式声明测试方法#[DataProvider(‘方法名’)]:把多组数据注入到测试方法#[Depends(‘testMethodName’)]:指定测试方法依赖关系#[Group(‘名称’)]:给测试分组(用于选择性运行)
项目配置(phpunit.xml)
在项目根目录创建 phpunit.xml 文件:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"
colors="true"
testdox="true"
failOnWarning="true">
<testsuites>
<testsuite name="Application Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>src</directory>
</include>
</source>
</phpunit>
然后直接运行 ./vendor/bin/phpunit 即可。
常见问题与避坑
- 命名空间不对:确保
src/和tests/下类的命名空间与 PSR-4 自动加载规则匹配。 - 私有方法无法直接测试:通过公共接口测试或使用反射(不推荐)。
- 静态方法难以 Mock:可将静态方法封装为实例方法,或使用 Mockery 库。
- 测试对象有构造参数:在
setUp()中创建真实对象,或者使用getMockBuilder部分模拟。
其他测试工具(补充)
- Mockery:更强大的 Mock 框架。
- Behat:行为驱动开发(BDD)测试。
- Laravel 专用:
RefreshDatabase、actingAs等测试辅助功能(如果你用 Laravel)。
总结流程
- 写代码 → 2. 写测试(测试目标生产代码) → 3. 运行测试 → 4. 查看覆盖率 → 5. 重构优化(确保测试通过)
单元测试的核心原则是:快速、隔离、可重复、自动化,从简单的纯函数开始测试,逐渐扩展到涉及外部依赖的复杂场景,刚开始可能会觉得耗时,但长期来看能显著减少回归 bug 并提高代码质量。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播