SuperAPI AI 工具集

symfony-yoandev-testing

测试与质量

查看项目

更新于 10-16 06:00

技能介绍

用途

该技能用于在真实的 Symfony 应用中以 TDD 方式编写和运行 PHPUnit 测试。其核心循环是:先写测试 → 运行 → 看到 RED → 写代码 → 看到 GREEN。技能强调“红色”本身才是重点,因为一个从未失败过的测试无法被信任——它可能因断言写反、替身过于宽松、或测试根本没运行而错误地变绿。

主要能力

测试循环与变异检查

先写测试、单独运行失败测试(使用 --filter 按方法名过滤),确认失败来自断言而非致命错误。对于无法先失败的声明式行为(验证属性、仓库中的 ORDER BY、路由、cascade: ['remove']、序列化组),采用变异检查:写测试并看到通过 → 故意破坏代码(如把 ASC 改成 DESC、把 min: 1 改成 min: 0、删除约束)→ 确认测试变红 → 恢复并确认变绿。若第三步仍为绿,说明测试没有测量任何东西,应删除。

每个行为单元应覆盖的内容

技能不设覆盖率百分比目标,而是提出五个行为问题:正常路径、边界值(最低/最高接受值及两侧第一个被拒绝的值)、错误(精确异常类型,如 expectException(BookNotFound::class))、安全(谁不被允许做这件事)、副作用(flush、邮件、消息派发,以及操作可重放时运行两次不等于运行两次)。边界和错误适合用 #[DataProvider],提供者方法必须是静态的(PHPUnit 10+)。

测试金字塔

  • 单元测试:基类 PHPUnit\Framework\TestCase,用于业务规则、DTO 验证、voters、输出规范化,无内核,毫秒级。
  • 集成测试:基类 KernelTestCase,用于仓库、DQL、映射等需要真实数据库的场景。
  • 功能测试:基类 WebTestCase,用于路由、表单、状态码、重定向、HTML 与 JSON 契约。

业务规则若只能通过 WebTestCase 验证,说明规则放错了位置,应移到服务或 DTO 约束中。若在功能测试中 mock 自己的服务,应停止并改写单元测试。

数据库隔离:dama/doctrine-test-bundle

安装命令:composer require --dev dama/doctrine-test-bundle。由于配方位于 recipes-contrib,Composer 会打印 IGNORING 而非自动应用,需要手动写两行:在 config/bundles.php 中添加 DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true],,并在 phpunit.dist.xml 中添加:

<extensions>
    <bootstrap class="DAMA\DoctrineTestBundle\PHPUnit\PHPUnitExtension"/>
</extensions>

两行必须同时写或同时不写。只注册扩展而不注册 bundle 会导致每个测试提交事务,套件保持绿色却在填充数据库。DAMA 在驱动层通过 PHPUnit 扩展挂钩,连接是静态的,能跨越内核重启,事务由 PHPUnit 事件系统开启和回滚。

技能解释了为何不用 setUp() 中手动 beginTransaction():在 WebTestCase 的第二个请求时内核会关闭并重启,连接被重建,事务不再存在,tearDown() 会抛出 NoActiveTransaction,且第二个请求起写入的行会被提交并残留。

测试替身

优先使用 Symfony 自带的内存实现:内存邮件器(assertEmailCount() / assertQueuedEmailCount())、MockHttpClient、in-memory:// Messenger 传输、MockClock。对于自己的协作者:createStub() 用于替身只是背景、输入值并断言其他内容;createMock() 仅在后面跟 expects() 时使用。PHPUnit 11 起,无期望的 mock 会发出 PHPUnit notice。$container->set() 仅用于外部边界(支付网关、短信提供商、第三方 API),绝不用于自己的服务。

使用方式

运行失败测试:vendor/bin/phpunit --filter it_refuses_a_rating_of_zero。安装 DAMA 后无需 setUp()、tearDown() 或基类,每个测试方法自动获得事务并在结束时回滚。

适用场景

适用于 Symfony 项目的 PHPUnit 测试编写与运行,尤其是需要 TDD 循环、测试金字塔分层、数据库隔离和测试替身选择的场景。

限制与范围

查询计数断言(N+1)属于 symfony-yoandev-performance;PHPStan、deptrac、php-cs-fixer、CI 工作流及携带 DAMA 扩展和 failOnPhpunitNotice 的 phpunit.dist.xml 属于 symfony-yoandev-quality;本地数据库与邮件器搭建属于 symfony-yoandev-local-dev。技能还列出常见陷阱(如测试首次运行即绿、WebTestCase 中 rollBack 抛 NoActiveTransaction、DAMA 已安装但行仍残留、单独通过但一起失败、测试写入开发数据库、JSON 断言 4 与 4.0、DataProvider 非静态、覆盖率元数据错误、邮件未到达、symfony console --env=test 命中开发数据库等)及版本注意事项(如 static::runCommand() 需 Symfony 8.1+、enableAttributeMapping() 为 7.0+、DBAL 4 的 beginTransaction(): void、dama/doctrine-test-bundle 8.x 对应 PHPUnit 10+、doctrine/data-fixtures 2.0 的 getReference() 需传类名等)。