如果您有一个 Symfony 项目,它向您的其他项目(无论是微服务、前端和 api 分离项目等)发出 HTTP 请求,您可能需要为您的测试模拟它们。
这是一个简单的解决方案,它允许您为 symfony 项目中的测试环境创建一个模拟自定义类,可用于您的单元或功能测试。
这个提议的解决方案是使用像http-mock这样的库的替代方案,它可能更难设置
假设我们有一个带有方法的 API Client 类,getResourceByPath($path)通过一个库(Guzzle、symfony 的 HttpClient、cURL 或其他)请求 API 端点并返回我们需要的 json
namespace AppBundle\Infra\Client;
class ApiClient
{
public function getResourceByPath(string $path): array
{
$response = $this->httpClient->get($path);
return json_decode($response->getBody());
}
}
并且这个类应该在你的config/services/client.yaml(对于 Symfony 4+ 项目,或者app/config.yml对于 Symfony 3)中声明
services:
AppBundle\Infra\Client\ApiClient: # (or app.client.api)
public: true
arguments: [...] # any arguments you need
由于我们不想实际执行请求,因此我们需要覆盖该方法的行为。
首先, ApiClient 需要一个接口,如果它还没有的话
namespace AppBundle\Infra\Client;
interface ApiClientInterface
{
public function getResourceByPath(string $path): array;
}
并使用以下命令编辑 ApiClient 类
class ApiClient implements ApiClientInterface { ... }
现在我们可以创建我们的模拟类,它将执行我们需要的任何逻辑,例如从我们的本地文件夹而不是 API 中检索预期的 JSON
namespace tests\Mock\Client;
class ApiClientMock implements ApiClientInterface
{
private $mockFolder = dirname(__DIR__) . '/resources/api';
public function getResourceByPath(string $path): array
{
$localFile = sprintf(
'%s/%s.json',
$this->mockFolder,
$path
);
return json_decode(
file_get_contents($localFile)
);
}
}
我们的测试文件夹的结构应该是这样的
tests/
Mock/
Client/
ApiClientMock.php
resources/
api/
article.json
....
您现在可以在config/services_test.yaml(或app/config_test.yml)中添加模拟声明
services:
AppBundle\Infra\Client\ApiClient: # (or app.client.api)
class: Tests\Mocks\ApiClientMock
运行测试时,您现在应该正确地从本地文件中检索内容
当然,此示例显示了逻辑的简化版本,您可以根据任何需要对其进行自定义。您可能希望对调用的文件和路径进行更多验证,或者在它们与本地文件之间创建映射。
该系统还可用于模拟任何其他可能调用外部服务的服务,如通知服务、邮件程序或任何可以写入数据库的服务,以避免潜在地向全世界共享测试数据
这个解决方案还有一个意想不到的好处:我们可以使用一个小技巧来使用模拟本地——如果测试神秘地失败并且我们需要调试;如果我们想直接检查页面渲染;或者,如果我们想要处理 API 中尚不可用的未来功能:通过test手动切换到环境(通过编辑web/app_dev.php或.env),并使用我们在本地检索的内容在浏览器上访问项目
发表评论 取消回复