You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()后仍存在方法调用不匹配或异常捕获失败的问题。

错误原因

  1. PHPUnit 9起,getMock()方法已被废弃,官方推荐使用createMock()或getMockBuilder();
  2. 直接使用createMock()Mock PDO、PDOStatement这类内置扩展类时,无法灵活配置构造函数禁用、方法白名单等;
  3. 原测试代码中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 14:05:21