在我的 Laravel 构建中,我有一个服务类:
use GuzzleHttp\Client;
use App\Services\ApiService\Exceptions\ServiceException
class ApiService {
__construct(
protected Client $client
) {
}
public function request() {
try {
$response = $this->client->get('/test');
} catch (Exception $e) {
throw new ServiceException($e->getMessage(), $e->getCode(), $e);
}
return response;
}
}
我的自定义异常类
ServiceException
看起来像这样:
class ServiceException extends Exception {
public function __construct($message, $code, $previous) {
parent::__construct($message, $code, $previous);
}
public function report() {
Log::error($this->getMessage());
}
}
我编写了一个测试用例,尝试验证当
Log::error
抛出 ApiService::request
时是否调用 ServiceException
:
test_api_service_logs_error_when_request_fails() {
$clientMock = new Client([
'handler' => HandlerStack::create(
new MockHandler([
new Response(500, [], 'Internal Server Error')
])
)
]);
Log::shouldReceive('error')
->once()
$service = new ApiService($clientMock);
$service->request();
}
当我运行测试时,出现错误:
来自 Mockery_0_Illuminate_Log_LogManager 的方法 error() 应该叫
据我了解,Laravel 应该检测
ServiceException::report
方法并触发 Log::error
,但情况似乎并非如此。 Laravel 在测试期间和实际运行时的执行之间显然存在行为差异,如果有人能启发我,我将不胜感激!
编辑: 我还应该补充一点,我尝试在使用
withoutExceptionHandling()
调用路线时使用 $this->get('/api/my-route')
,但仍然没有接听 report()
差异不在于 Laravel,而在于你对测试和异常的理解。
根据文档: https://laravel.com/docs/10.x/http-tests#exception-handling
assertThrows 方法可用于断言给定范围内的代码 闭包抛出指定类型的异常:
$this->assertThrows(
fn () => (new ProcessOrder)->execute(),
OrderInvalid::class
);
另请阅读
withoutExceptionHandling()
,其中指出:
有时您可能想测试您的应用程序是否抛出异常 具体异常。确保异常不会被捕获 通过 Laravel 的异常处理程序并作为 HTTP 响应返回,您 可以在进行之前调用 withoutExceptionHandling 方法 要求:
您也不需要测试 Laravel 的核心功能,因为这有点多余,因为您的异常正在处理日志记录。
你应该测试的是是否抛出异常。
test_api_service_logs_error_when_request_fails() {
$clientMock = new Client([
'handler' => HandlerStack::create(
new MockHandler([
new Response(500, [], 'Internal Server Error')
])
)
]);
$this->assertThrows(
fn () => (new ApiService($clientMock))->request(),
ServiceException::class
);
}