PHPUnit9.6.8+调用getMock()报未定义方法错误,createMock也异常
PHPUnit 9+ 中Mock PDO及解决getMock/createMock报错问题
问题场景
使用PHPUnit 9.6.8+版本测试Models\Report类的getReport方法,尝试Mock PDO及PDOStatement对象时,执行测试命令docker compose --profile tools run phpunit出现错误:
Error: Call to undefined method Tests\Unit\ReportTest::getMock()
替换为createMock()后仍存在方法调用不匹配或异常捕获失败的问题。
错误原因
- PHPUnit 9起,
getMock()方法已被废弃,官方推荐使用createMock()或getMockBuilder(); - 直接使用
createMock()Mock PDO、PDOStatement这类内置扩展类时,无法灵活配置构造函数禁用、方法白名单等; - 原测试代码中
expectException()声明位置错误,且未完整Mock业务方法调用链中的所有方法。
修正后的测试代码
<?php declare(strict_types=1); namespace Tests\Unit; use PHPUnit\Framework\TestCase; use Models\Report; use PDO; use PDOStatement; use PDOException; class ReportTest extends TestCase { public function testReportThrowsExceptionWhenQueryNotFound(): void { // Mock PDOStatement 对象 $statementMock = $this->getMockBuilder(PDOStatement::class) ->disableOriginalConstructor() ->getMock(); // 配置Statement方法的调用预期 $statementMock->expects($this->once()) ->method('bindValue') ->with(':slug', 'testSlug', PDO::PARAM_STR); $statementMock->expects($this->once()) ->method('execute') ->willReturn(true); $statementMock->expects($this->once()) ->method('fetchColumn') ->willReturn(false); // Mock PDO 对象 $pdoMock = $this->getMockBuilder(PDO::class) ->disableOriginalConstructor() ->onlyMethods(['prepare']) // 替代已废弃的setMethods() ->getMock(); $pdoMock->expects($this->once()) ->method('prepare') ->with("select query_sql from reports WHERE slug=:slug limit 1") ->willReturn($statementMock); // 声明期望抛出的异常 $this->expectException(PDOException::class); $this->expectExceptionMessage("Unable to find report"); // 执行测试方法 $report = new Report($pdoMock); $report->getReport('testSlug'); } }
关键修改点
- 废弃方法替换:用
onlyMethods()替代已废弃的setMethods(),明确指定需要Mock的方法;用getMockBuilder()创建Mock对象,支持禁用构造函数等自定义配置; - 异常声明顺序:
expectException()必须放在触发异常的代码之前,确保PHPUnit能正确捕获并验证异常; - 完整调用链Mock:业务方法
getQuery()依次调用了prepare、bindValue、execute、fetchColumn,需为所有这些方法设置Mock行为,保证测试流程完整; - 代码优化:引入对应类的命名空间,避免全局命名空间调用,提升代码可读性。
业务类说明
Models\Report的getReport()方法会调用受保护的getQuery()获取SQL语句,当getQuery()返回false时,抛出PDOException。上述测试用例验证了这一异常触发逻辑。
内容的提问来源于stack exchange,提问作者cookie
相关产品推荐
相关产品推荐

