如何编写PHPUnit测试验证testLink方法中authorize的调用逻辑
我们有一个testLink方法,其内部会在两种场景下调用$this->authorize()方法,需要编写单元测试来验证这部分业务逻辑。
目标方法代码
public function testLink($itemId): bool { $token = $this->settingRepository->getValue(self::SETTING_ADMITAD_TOKEN); if ($token) { $this->token = $token; } if (!$this->token) { $this->authorize(); } // 注:原代码中$response变量未显式初始化,推测此处应有$response = $this->validateLinkRequest($itemId); if ($response->getStatusCode() === 401) { $this->statusCode = 401; $this->authorize(); $response = $this->validateLinkRequest($itemId); } if ($response->getStatusCode() === 200 && json_decode($response->getContent())->message === self::ADMITAD_SUCCESS_RESPONSE) { return true; } else { return false; } }
项目已有单元测试示例
public function testAuthorize() { $mockHttpClient = new MockHttpClient( [ new MockResponse( json_encode([ "error_description" => "Token is expired", "status_code" => 401, "error_code" => 0, "error" => "invalid_token" ]), [ 'response_headers' => [ 'content-type' => 'application/json', ], 'http_code' => 401, ] ), ] ); self::$container->set(HttpClientInterface::class, $mockHttpClient); $provider = self::$container->get(AdmitadDataProvider::class); $response = $provider->validateLinkRequest(self::ITEM_ID_1); $this->expectException(ClientException::class); $this->expectExceptionCode(401); }
单元测试编写指导
我们需要针对authorize()的三种调用场景分别编写测试:
场景1:无配置token,首次请求成功(非401)
此时testLink会因$this->token不存在调用一次authorize(),后续请求成功无需再次调用。
public function testTestLinkCallsAuthorizeOnceWhenNoTokenAndRequestSucceeds() { // 1. Mock SettingRepository,返回空token $mockSettingRepo = $this->createMock(SettingRepository::class); $mockSettingRepo->method('getValue') ->with(self::SETTING_ADMITAD_TOKEN) ->willReturn(null); // 2. Mock validateLinkRequest返回200成功响应 $mockSuccessResponse = new MockResponse( json_encode(['message' => self::ADMITAD_SUCCESS_RESPONSE]), ['http_code' => 200, 'response_headers' => ['content-type' => 'application/json']] ); $mockHttpClient = new MockHttpClient([$mockSuccessResponse]); self::$container->set(HttpClientInterface::class, $mockHttpClient); // 3. 创建被测对象,替换依赖并mock authorize方法 $mockProvider = $this->getMockBuilder(AdmitadDataProvider::class) ->setConstructorArgs([self::$container]) ->onlyMethods(['authorize']) ->getMock(); $mockProvider->settingRepository = $mockSettingRepo; $mockProvider->expects($this->once()) ->method('authorize'); // 4. 执行测试方法 $result = $mockProvider->testLink(self::ITEM_ID_1); $this->assertTrue($result); }
场景2:有配置token,但首次请求返回401
此时$this->token存在,不会触发首次authorize();但因请求返回401,会调用一次authorize(),重新请求后成功。
public function testTestLinkCallsAuthorizeOnceWhenTokenExistsButFirstRequestFails() { // 1. Mock SettingRepository返回有效token $mockSettingRepo = $this->createMock(SettingRepository::class); $mockSettingRepo->method('getValue') ->with(self::SETTING_ADMITAD_TOKEN) ->willReturn('valid_token'); // 2. Mock HttpClient先返回401,再返回200成功响应 $mockResponses = [ new MockResponse( json_encode(['error' => 'invalid_token']), ['http_code' => 401, 'response_headers' => ['content-type' => 'application/json']] ), new MockResponse( json_encode(['message' => self::ADMITAD_SUCCESS_RESPONSE]), ['http_code' => 200, 'response_headers' => ['content-type' => 'application/json']] ) ]; $mockHttpClient = new MockHttpClient($mockResponses); self::$container->set(HttpClientInterface::class, $mockHttpClient); // 3. 创建被测对象并mock authorize方法 $mockProvider = $this->getMockBuilder(AdmitadDataProvider::class) ->setConstructorArgs([self::$container]) ->onlyMethods(['authorize']) ->getMock(); $mockProvider->settingRepository = $mockSettingRepo; $mockProvider->expects($this->once()) ->method('authorize'); // 4. 执行测试 $result = $mockProvider->testLink(self::ITEM_ID_1); $this->assertTrue($result); }
场景3:无配置token,首次请求返回401
此时会先因无token调用一次authorize(),再因请求401调用第二次authorize(),最终请求成功。
public function testTestLinkCallsAuthorizeTwiceWhenNoTokenAndFirstRequestFails() { // 1. Mock SettingRepository返回空token $mockSettingRepo = $this->createMock(SettingRepository::class); $mockSettingRepo->method('getValue') ->with(self::SETTING_ADMITAD_TOKEN) ->willReturn(null); // 2. Mock HttpClient先返回401,再返回200成功响应 $mockResponses = [ new MockResponse( json_encode(['error' => 'invalid_token']), ['http_code' => 401, 'response_headers' => ['content-type' => 'application/json']] ), new MockResponse( json_encode(['message' => self::ADMITAD_SUCCESS_RESPONSE]), ['http_code' => 200, 'response_headers' => ['content-type' => 'application/json']] ) ]; $mockHttpClient = new MockHttpClient($mockResponses); self::$container->set(HttpClientInterface::class, $mockHttpClient); // 3. 创建被测对象并mock authorize方法 $mockProvider = $this->getMockBuilder(AdmitadDataProvider::class) ->setConstructorArgs([self::$container]) ->onlyMethods(['authorize']) ->getMock(); $mockProvider->settingRepository = $mockSettingRepo; $mockProvider->expects($this->exactly(2)) ->method('authorize'); // 4. 执行测试 $result = $mockProvider->testLink(self::ITEM_ID_1); $this->assertTrue($result); }
关键注意事项
- 使用PHPUnit的
getMockBuilder来mockauthorize()方法,通过expects()断言调用次数是否符合预期 - 针对不同场景Mock
SettingRepository的返回值,控制是否触发首次authorize() - 用
MockHttpClient模拟validateLinkRequest的不同响应,控制是否触发第二次authorize() - 原代码中
$response变量未显式初始化,需补充$response = $this->validateLinkRequest($itemId);逻辑,否则测试会报错
内容的提问来源于stack exchange,提问作者Ilya Mironchikov
相关产品推荐
相关产品推荐

