在 symfony 7.1 中创建 phpunit 测试需严格遵循自动加载规则与内核初始化机制:测试类命名空间须为 app\tests,文件名与类名完全一致;依赖服务时继承 kerneltestcase 并调用 bootkernel() 获取容器;模拟依赖用 createmock() 并通过 expects() 验证交互;运行前确保 phpunit.xml.dist 配置正确,异常测试需提前声明 expectexception()。

在 Symfony 7.1 中创建可运行、可维护的 PHPUnit 测试用例,必须严格匹配新版自动加载规则与内核初始化机制,否则测试类无法被识别或容器始终为空。
创建标准测试类文件结构
在项目根目录下执行:mkdir -p tests/Service→touch tests/Service/PriceCalculatorTest.php。
打开该文件,写入以下内容(注意命名空间必须以 App\Tests 开头,且路径需与源码对应):
namespace App\Tests\Service;
use App\Service\PriceCalculator;
use PHPUnit\Framework\TestCase;
class PriceCalculatorTest extends TestCase
{
public function testCalculatesTotalWithVat(): void
{
$calculator = new PriceCalculator();
$result = $calculator->calculate(100, 0.2);
$this->assertSame(120.0, $result);
}
}
文件名 PriceCalculatorTest.php 必须与类名完全一致;若写成 pricecalculatorTest.php 或 PriceCalcTest.php,Composer autoloader 将完全忽略该文件。
测试依赖服务:使用 KernelTestCase 启动容器
当被测逻辑涉及 Doctrine、Mailer、Cache 等服务时,不能仅用 TestCase,必须继承 Symfony\Bundle\FrameworkBundle\Test\KernelTestCase。
第一步:在测试类顶部替换 use 声明:
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
第二步:在测试方法开头调用 $this->bootKernel() —— 这是唯一能获取有效容器的方式。不调用则 $this->getContainer() 返回 null,后续所有服务注入都会失败。
第三步:从容器中取出服务并验证行为:
public function testSendsEmailOnOrderComplete(): void
{
$this->bootKernel();
$mailer = $this->getContainer()->get('mailer');
$this->assertInstanceOf(\Symfony\Component\Mailer\MailerInterface::class, $mailer);
}
模拟外部依赖:MockObject 防止真实调用
方法一:基础 mock 创建与行为声明
引入 use PHPUnit\Framework\MockObject\MockObject; → 调用 $this->createMock(LoggerInterface::class) → 设置期望调用次数与方法名。
方法二:强制验证协作逻辑(关键点)
$logger = $this->createMock(LoggerInterface::class);
$logger->expects($this->once())
->method('error')
->with($this->stringContains('payment failed'));
如果被测代码实际调用了 error() 但参数不匹配,或根本没调用,测试立即失败 —— 这不是断言值,而是断言“是否按约定与协作对象交互”。
方法三:传入 mock 到服务构造函数(适用于手动实例化)
直接将 mock 对象作为参数传给被测服务:$service = new PaymentProcessor($logger, $apiClient);。不要试图在容器里替换服务,那样会污染全局状态。
运行测试并捕获异常
第一步:确保 phpunit.xml.dist 存在且包含 <testsuites></testsuites> 配置,否则 PHPUnit 不会扫描 tests/ 目录。
第二步:执行命令:./vendor/bin/phpunit --testdox tests/Service/PriceCalculatorTest.php。
第三步:验证异常抛出场景(例如未来日期触发 InvalidArgumentException):
public function testThrowsExceptionOnFutureDate(): void
{
$this->expectException(\InvalidArgumentException::class);
$filter = new ElapsedFilter();
$filter->elapsedFilter(new \DateTime('+5 seconds'));
}
这一步必须放在调用被测方法之前,否则异常未被捕获导致测试中断而非通过。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











