引言:为什么要测试PHP应用程序?
代码测试不仅仅是一种时尚趋势,而是专业开发的基本实践。在PHP世界中,大量项目与数据库、外部API和复杂的业务逻辑打交道,代码质量直接影响产品的稳定性和安全性。没有测试,即使很小的改动也可能破坏已经运行多年的功能。
在本文中,我们将分析三个关键的测试层级:unit(单元测试)、integration(集成测试)和e2e(端到端测试)。您将了解它们的区别、何时使用每种测试,并看到PHP的实际代码示例。无论您使用Laravel、Symfony还是纯PHP编写代码,这些知识都将帮助您构建可靠的应用程序。
单元测试:检查隔离的组件
单元测试是最底层、最快速的测试层级。其目标是完全隔离外部依赖(数据库、文件系统、HTTP请求)的情况下,检查单个方法或函数的工作情况。
PHP单元测试工具
- PHPUnit — 事实上的标准。功能强大、灵活,受大多数框架支持。
- Pest — 语法更简洁的现代替代方案。非常适合初学者和重视可读性的团队。
PHPUnit示例
假设我们有一个简单的折扣计算类:
<?phpclass DiscountCalculator{ public function calculate(float $price, float $percent): float { if ($percent < 0 || $percent > 100) { throw new \\InvalidArgumentException('折扣百分比必须在0到100之间'); } return $price - ($price * $percent / 100); }}?>该类的测试如下所示:
<?phpuse PHPUnit\\Framework\\TestCase;
class DiscountCalculatorTest extends TestCase{ public function testCalculateWithValidDiscount(): void { $calculator = new DiscountCalculator(); $result = $calculator->calculate(1000, 20); $this->assertEquals(800.0, $result); }
public function testCalculateWithZeroPercent(): void { $calculator = new DiscountCalculator(); $result = $calculator->calculate(500, 0); $this->assertEquals(500.0, $result); }
public function testCalculateThrowsExceptionForInvalidPercent(): void { $this->expectException(\\InvalidArgumentException::class); $calculator = new DiscountCalculator(); $calculator->calculate(100, 150); }}?>单元测试的关键原则:
- 一个测试只做一项检查(一个assert)。
- 测试之间不应相互依赖。
- 使用模拟对象(mocks)隔离外部服务。例如,在PHPUnit中使用
createMock()。 - 覆盖边界情况:null、空字符串、负值。
集成测试:检查组件间的交互
集成测试检查应用程序的不同部分如何协同工作:类、数据库、外部服务。与单元测试不同,这里我们使用真实(或接近真实)的依赖。
何时编写集成测试?
- 检查与数据库的交互(ORM、查询)。
- 处理文件系统(上传/读取文件)。
- 与外部API交互(通过测试桩)。
- 检查仓库和服务层的正确性。
使用PDO的PHP示例(无框架)
<?phpuse PHPUnit\\Framework\\TestCase;
class User