编写第一个测试:测试类与测试方法命名规范、assert方法概览、运行测试

好,咱们现在开始动手写第一个测试。

说实话,很多初学者卡就卡在这一步——不是不会写代码,而是不知道「测试该长什么样」。我当年带团队时,有个同事写了三年 PHP,第一次写测试时居然把测试类命名成了 test.php。嗯,这当然也能跑,但团队里其他人看到会疯掉的。

测试类与测试方法的命名规范

先定规矩。PHPUnit 对命名有约定,说白了就是「望文生义」。

测试类的命名

  • 类名必须以 Test 结尾。比如 UserServiceTestOrderControllerTest
  • 类名通常对应被测试的类名。你测 UserService,测试类就叫 UserServiceTest
  • 文件命名必须和类名一致,且放在 tests/ 目录下

我个人习惯:测试类名用「被测试类 + Test」这种模式。别搞什么花哨的 UserServiceTestCases 或者 TestUserService,团队里每个人看到 XxxTest 就知道这是测试文件。

测试方法的命名

方法名要能说清楚「测什么、什么场景、期望什么结果」。我推荐这种模式:

test[被测方法]_[场景]_[期望结果]

举个例子:

class UserServiceTest extends TestCase
{
    public function testCreateUser_WithValidData_ReturnsUserId()
    {
        // 测试创建用户,传入合法数据,期望返回用户ID
    }

    public function testCreateUser_WithEmptyName_ThrowsException()
    {
        // 测试创建用户,传入空名字,期望抛出异常
    }
}

你想想看,三个月后你回来看这段代码,是不是一眼就知道每个方法在测什么?

避坑指南:我曾经见过有人用中文写方法名,比如 test创建用户成功。虽然 PHP 允许,但 IDE 的自动补全和重构工具对中文支持很差。老老实实用英文驼峰命名吧。

assert 方法概览

测试的核心就是「断言」——判断实际结果和预期是否一致。PHPUnit 提供了几十种 assert 方法,但常用的其实就这几个:

方法 用途 示例
assertEquals() 判断两个值是否相等(宽松比较) $this->assertEquals(10, $result);
assertSame() 判断两个值是否全等(严格比较,类型也一致) $this->assertSame(10, $result);
assertTrue() 判断是否为 true $this->assertTrue($isValid);
assertFalse() 判断是否为 false $this->assertFalse($hasError);
assertNull() 判断是否为 null $this->assertNull($user);
assertNotNull() 判断是否不为 null $this->assertNotNull($user);
assertCount() 判断数组或集合的元素个数 $this->assertCount(3, $items);
assertInstanceOf() 判断对象是否为指定类的实例 $this->assertInstanceOf(User::class, $user);

注意assertEqualsassertSame 的区别。前者用 == 比较,后者用 ===。比如 assertEquals(1, '1') 会通过,但 assertSame(1, '1') 会失败。我在项目中踩过这个坑——一个接口返回了字符串类型的数字,我用 assertEquals 测了没问题,上线后前端报类型错误。从那以后,我统一用 assertSame

运行测试

写好了测试,怎么跑?三种方式:

1. 命令行直接跑

./vendor/bin/phpunit tests/UserServiceTest.php

跑单个文件,开发时最常用。

2. 跑整个 tests 目录

./vendor/bin/phpunit

不加参数,默认跑 tests/ 下所有测试。提交代码前记得跑一遍。

3. 过滤特定方法

./vendor/bin/phpunit --filter testCreateUser

只跑方法名包含 testCreateUser 的测试。调试时特别好用。

我个人习惯:在 IDE 里配置一个快捷键,一键运行当前文件。PhpStorm 里是 Ctrl+Shift+F10(Windows)或 Cmd+Shift+R(Mac)。写一行代码,按一下快捷键,看到绿色条,心里就踏实了。

第一个完整的测试示例

来,咱们写一个完整的。假设有个 Calculator 类:

// src/Calculator.php
class Calculator
{
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }
}

对应的测试:

// tests/CalculatorTest.php
use PHPUnit\Framework\TestCase;

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

    public function testAdd_WithNegativeNumbers_ReturnsSum()
    {
        $calculator = new Calculator();
        $result = $calculator->add(-1, -2);
        
        $this->assertSame(-3, $result);
    }
}

跑一下:

./vendor/bin/phpunit tests/CalculatorTest.php

PHPUnit 10.5.0 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 0.01 seconds, Memory: 6.00 MB

OK (2 tests, 2 assertions)

看到那两个点了吗?每个点代表一个通过的测试。如果失败会显示 F,并告诉你哪一行断言失败了。

核心要点

  • 测试类名 = 被测试类 + Test
  • 测试方法名 = test + 方法名 + 场景 + 期望
  • 断言用 assertSame 代替 assertEquals,更严格
  • 命令行跑测试,看到绿色就对了

嗯,第一个测试就这么简单。别想得太复杂,测试说白了就是「写一段代码,验证另一段代码对不对」。你平时手动测的时候不也是输入几个值,看看结果对不对吗?现在只是把这个过程自动化了而已。

下一章咱们聊聊「测试替身」——当你的代码依赖数据库、API 或者文件系统时,怎么优雅地测试。