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
相关产品推荐
相关产品推荐

