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

PHPUnit中模拟测试时实例化类的方法未生效问题求助

问题原因

你创建的Mock对象和接口代码里的new CurlRequest实例完全无关——测试里的$mock只是一个单独的对象,接口执行时会重新创建全新的CurlRequest实例,自然不会触发你定义的Mock行为。

解决方案

要让Mock生效,核心是让接口代码使用你测试中创建的Mock实例,而不是自己new新对象,常用两种方式:

方式一:依赖注入(推荐)

1. 修改接口所在类的代码,通过构造/方法注入CurlRequest

假设你的接口逻辑在ApiController里,修改为依赖注入方式:

class ApiController
{
    private $curlRequest;

    // 构造函数注入CurlRequest实例
    public function __construct(CurlRequest $curlRequest)
    {
        $this->curlRequest = $curlRequest;
    }

    public function myApiCall()
    {
        // 不再new,直接使用注入的实例
        $this->curlRequest->setOption(CURLOPT_USERPWD, "user-password");
        $this->curlRequest->setOption(CURLOPT_CUSTOMREQUEST, 'MLSD');
        // 修正原代码的setOption参数错误:应该是两个参数
        $this->curlRequest->setOption(CURLOPT_PROTOCOLS, CURLPROTO_SFTP);
        $response = $this->curlRequest->execute();
        die($response);
    }
}

2. 修改测试用例,将Mock实例注入到容器/控制器中

以Laravel框架为例,通过容器绑定Mock实例:

/** @test */
public function check_invalid_connection()
{
    // 创建CurlRequest的Mock,指定需要Mock的方法
    $mock = $this->getMockBuilder(CurlRequest::class)
        ->onlyMethods(['execute'])
        ->setConstructorArgs(["any-url"])
        ->getMock();

    // 设定Mock的execute方法抛出异常
    $mock->method("execute")
        ->willThrowException(new Exception("Bla"));

    // 将Mock实例绑定到容器,接口代码会从容器获取该实例
    $this->app->instance(CurlRequest::class, $mock);

    // 发起接口请求
    $response = $this->json('POST', '/my-api-call');

    // 添加断言验证结果,比如检查500状态码
    $response->assertStatus(500);
}

方式二:使用工厂类封装实例创建(适配不愿大改代码的场景)

1. 创建CurlRequest工厂类

class CurlRequestFactory
{
    public static function create(string $url): CurlRequest
    {
        return new CurlRequest($url);
    }
}

2. 修改接口代码,用工厂方法替代new操作

// 替换原有的new CurlRequest("any-url")
$req = CurlRequestFactory::create("any-url");
$req->setOption(CURLOPT_USERPWD,"user-password");
$req->setOption(CURLOPT_CUSTOMREQUEST, 'MLSD');
$req->setOption(CURLOPT_PROTOCOLS, CURLPROTO_SFTP);
$response = $req->execute();
die($response);

3. 测试时Mock工厂类的静态方法

如果使用PHPUnit原生Mock,需要注意静态方法Mock的限制,也可以用Mockery简化:

/** @test */
public function check_invalid_connection()
{
    $mock = $this->getMockBuilder(CurlRequest::class)
        ->onlyMethods(['execute'])
        ->setConstructorArgs(["any-url"])
        ->getMock();

    $mock->method("execute")
        ->willThrowException(new Exception("Bla"));

    // 用Mockery Mock工厂类的静态方法,返回我们创建的Mock实例
    Mockery::mock('overload:CurlRequestFactory')
        ->shouldReceive('create')
        ->with("any-url")
        ->andReturn($mock);

    $response = $this->json('POST', '/my-api-call');
}
额外注意点

你原接口代码中的setOption调用存在参数错误:$req->setOption(CURLOPT_USERPWD, CURLOPT_PROTOCOLS, CURLPROTO_SFTP);,该方法只接收两个参数(选项常量和对应值),需要修正为$req->setOption(CURLOPT_PROTOCOLS, CURLPROTO_SFTP);,否则实际运行会抛出参数数量错误。

内容的提问来源于stack exchange,提问作者Frnak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 22:52:23