TDD在PHP中:为真实项目进行测试驱动开发

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

为什么TDD成为PHP开发者的标准?

想象一下:您编写代码,运行它,看到错误,修复它——然后如此循环。熟悉吗?现在想象一下,您先编写一个注定失败的测试,然后编写最少的代码使其通过,最后才进行重构。这就是TDD在PHP中——测试驱动开发,它将混乱转变为有序的系统。

许多开发者害怕TDD:“这会拖慢开发速度!”,“我不知道如何测试遗留代码”,“PHPUnit很复杂”。但实际上,TDD节省了数小时的调试时间,并使代码能够抵御变化。在本文中,我们将通过真实的PHP示例来剖析TDD,展示“红-绿-重构”循环如何工作,并提供现成的实施模板。



什么是TDD,它在PHP中如何工作?

测试驱动开发(Test-Driven Development)是一种在实现之前编写测试的方法论。基本循环如下:

  • 红色——编写一个不通过的测试(预期错误)。
  • 绿色——编写最少的代码使测试通过。
  • 重构——改进代码,不改变行为。

在PHP中,TDD最常使用PHPUnit——一个强大的单元测试框架。但TDD关乎的是纪律,而非工具。让我们看看它在实践中如何工作。



示例1:测试一个简单的计算器

假设我们需要一个两数相加的函数。没有TDD,我们会这样写:

function add($a, $b) {    return $a + $b;}echo add(2, 3); // 5

使用TDD,我们首先编写测试:

use PHPUnit\\Framework\\TestCase;

class CalculatorTest extends TestCase { public function testAdd() { $calculator = new Calculator(); $result = $calculator->add(2, 3); $this->assertEquals(5, $result); }}

运行——测试失败(红色)。编写最少的实现:

class Calculator {    public function add($a, $b) {        return $a + $b;    }}

测试通过(绿色)。不需要重构——代码很简单。但如果我们想添加对负数的处理,我们会先为这种情况编写测试。



示例2:使用TDD进行数据库操作

人们常说:“TDD不适用于数据库”。这是误解。使用模拟(mocks)和测试数据库。来看一个UserRepository的示例:

class UserRepositoryTest extends TestCase {    public function testFindUserById() {        $pdoMock = $this->createMock(PDO::class);        $stmtMock = $this->createMock(PDOStatement::class);                $pdoMock->method('prepare')                ->willReturn($stmtMock);        $stmtMock->method('fetch')                 ->willReturn(['id' => 1, 'name' => 'Alex']);                $repository = new UserRepository($pdoMock);        $user = $repository->findById(1);                $this->assertEquals('Alex', $user['name']);    }}

测试验证了仓库正确调用了SQL并处理了结果。实现代码将是最少的:只需执行查询并返回数据。



PHP中TDD的流行工具

要使TDD成为您工作流程的一部分,您需要掌握几个工具:

  • PHPUnit——主要的测试框架。安装:composer require --dev phpunit/phpunit。
  • Mockery——用于创建具有灵活API的模拟对象的库。
  • Prophecy——Mockery的替代品,常与Symfony一起使用。
  • PHPStan / Psalm——静态分析工具,通过发现运行测试前的错误来补充TDD。

对于集成测试,可以使用Laravel Dusk或Symfony Panther,但作为开始,足够

博客

书籍推荐