PHP 怎么变异测试

wen PHP项目 2

本文目录导读:

PHP 怎么变异测试

  1. 主要的变异测试工具
  2. 安装与配置 Infection
  3. 运行变异测试
  4. 理解变异测试结果
  5. 变异测试指标
  6. 在 CI/CD 中集成
  7. 实用技巧
  8. 完整配置文件示例
  9. 常见问题与解决
  10. 推荐工作流程

在 PHP 中进行变异测试,主要是通过引入变异测试工具,在代码中注入缺陷(变异体),然后运行测试套件来检测现有测试是否能够发现这些变异,如果测试未能发现某个变异,说明该变异的对应代码段缺乏足够的测试覆盖。

以下是 PHP 变异测试的完整指南:

主要的变异测试工具

Infection(最流行)

Infection 是目前 PHP 生态中最成熟、最活跃的变异测试框架。

Humbug

Humbug 是较早的变异测试工具,但已不再维护,现在推荐使用 Infection。


安装与配置 Infection

安装

使用 Composer 安装:

composer require --dev infection/infection

基本配置

创建 infection.json 配置文件:

{
    "$schema": "https://raw.githubusercontent.com/infection/infection/master/resources/schema.json",
    "source": {
        "directories": [
            "src"
        ]
    },
    "timeout": 10,
    "logs": {
        "text": "infection.log"
    },
    "mutators": {
        "global-ignores": [
            "src/Adapters/"
        ]
    }
}

或者使用命令行直接指定源目录:

vendor/bin/infection --source=src --test-framework=phpunit --covered-only

运行变异测试

基本运行

vendor/bin/infection

高级运行选项

# 仅测试已覆盖的代码(更快)
vendor/bin/infection --covered-only
# 指定测试框架(PHPUnit 或 PHPSpec)
vendor/bin/infection --test-framework=phpunit
# 限制变异数量(加速测试)
vendor/bin/infection --max-mutations=100
# 跳过未覆盖代码
vendor/bin/infection --skip-covered

理解变异测试结果

运行后会生成类似以下的输出:

Processing source code files: 50
Processing test classes: 100
...
2 mutations were generated:
   1) /path/to/file.php:76    [M] PublicVisibility
   --- Original
   +++ New
   @@ @@
   -    public function calc()
   +    protected function calc()
      Mutation was not detected by tests

结果类型

  • Killed:测试发现了变异,说明该代码被充分测试
  • Escaped:测试未发现变异,需要增加测试
  • Uncovered:变异代码从未被执行,需要添加测试
  • Timeout:测试运行超时

变异测试指标

变异测试的核心指标是 MSI(Mutation Score Indicator)

MSI = (Killed Mutants / Total Mutants) × 100

目标:通常建议 MSI 达到 80% 以上。


在 CI/CD 中集成

在 GitLab CI 或 GitHub Actions 中:

# GitHub Actions 示例
name: Mutation Testing
on: [push]
jobs:
  mutation-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.1'
      - run: composer install
      - run: vendor/bin/infection --min-msi=80 --covered-only
        env:
          CI: true

实用技巧

忽略不可测试的代码

{
    "source": {
        "directories": [
            "src"
        ],
        "exclude": [
            "src/Config",
            "src/Models/Entity"
        ]
    },
    "mutators": {
        "global-ignores": [
            "src/Kernel.php",
            "src/Doctrine/"]
    }
}

只测试特定类

# 只测试 User 类的变异
vendor/bin/infection --filter=User

提高运行速度

  • 使用 --threads=4 并行执行
  • 使用 --covered-only 只变异已覆盖代码
  • 限制最大变异数:--max-mutations=500

与 PHPUnit 协作

确保 PHPUnit 测试快速执行,可以设置 --coverage

# 生成覆盖率并只测试剩余代码
vendor/bin/infection --coverage=coverage --min-msi=85

完整配置文件示例

{
    "$schema": "https://raw.githubusercontent.com/infection/infection/master/resources/schema.json",
    "source": {
        "directories": ["src/"]
    },
    "logs": {
        "text": "reports/infection.txt",
        "html": "reports/infection.html",
        "github": "true" 
    },
    "mutators": {
        "global-ignores": [
            "src/Entity/*",
            "src/DTO/*"
        ],
        "@default": true,
        "CastInt": false,
        "DecrementInteger": false
    },
    "min-msi": 85,
    "min-covered-msi": 90,
    "threads": 4,
    "timeout": 10,
    "executableFinder": {
        "phpunit": "vendor/bin/phpunit"
    }
}

常见问题与解决

问题 解决方案
测试太慢 增加 --threads,使用 --covered-only
变异逃脱太多 审查被漏掉的测试,增加边界条件测试
误报变异 使用 global-ignores 忽略特定代码
CI 内存不足 设置 MEMORY_LIMIT=-1 或增加 PHP 内存限制
覆盖率高但 MSI 低 检查测试断言是否过于宽泛

推荐工作流程

# 1. 首先运行正常测试确保通过
composer test
# 2. 生成覆盖率报告
vendor/bin/phpunit --coverage-xml=coverage/coverage-xml
# 3. 运行变异测试
vendor/bin/infection --coverage=coverage --min-msi=85
# 4. 查看报告并补充测试
open reports/infection.html

变异测试是提升测试质量的重要手段,通过 Infection,你可以:

  • 准确衡量测试的有效性
  • 发现测试盲区
  • 不断提高 MSI 直至达到理想水平(80%+)
  • 防止回归测试不充分的问题

建议先从关键业务逻辑代码开始,逐步推广到全项目,因为变异测试运行时间较长(可能是普通测试的 10-20 倍),需要对速度和覆盖进行平衡。

抱歉,评论功能暂时关闭!