【问题标题】:Symfony 5.2 - How to test a class with a dependency on the cache interfaceSymfony 5.2 - 如何测试依赖于缓存接口的类
【发布时间】:2020-12-17 13:47:01
【问题描述】:

我正在使用作为框架项目安装并在 PHP 7.4 上运行的 Symfony 5.2 安装:最新

我在类中使用Symfony\Contracts\Cache\TagAwareCacheInterface 作为自动连接的构造函数注入依赖项。

我想缓存从配置端点获取的开放 ID 响应:

$config = $this->cachePool->get(
    'openid-config',
    function (ItemInterface $item) {
        $item->expiresAfter(self::CACHE_TIME_SECONDS);
        $webContent = file_get_contents($this->openIdConfigurationUrl);
        if (false === $webContent) {
            $message = "Failed to fetch openid config from web at [{$this->openIdConfigurationUrl}]";
            $this->logger->error($message);
            throw new CannotReadOpenIdConfigException($message);
        }
        return $webContent;
    }
);

我想对我的班级进行单元测试。

Symfony documentation 不提供上述可调用语法的替代方法。

我尝试使用模拟构建器创建缓存模拟:

return $this->getMockBuilder('Symfony\Contracts\Cache\TagAwareCacheInterface')
            ->disableOriginalConstructor()
            ->getMock();

我找不到方法让它在我的被测对象中执行可调用对象。

所以,我尝试使用实际的 liveCacheClient 而不是模拟这种依赖关系。我可以通过在我的测试代码中添加或删除键来控制它的内容(很恶心,但我无法模拟工作)

$liveCacheClient = (self::$container)->get(TagAwareCacheInterface::class);
$liveCacheClient->clear();

如果我尝试使用容器来获取缓存的真实实例,则会收到 Symfony 已从容器中删除类的错误:

Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: The "Symfony\Contracts\Cache\TagAwareCacheInterface" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.

那么,在 Symfony 缓存中正确地对代码进行单元测试的正确方法是什么?

【问题讨论】:

  • 测试这类事情总是很棘手。 This answer 展示了如何公开私有服务。不确定它是否真的有帮助。你也可以看看缓存组件的 Tests 目录,看看 Symfony 是如何测试它的。
  • 使用file_get_contents 会使这变得更加困难 - 如果您可以使用 Guzzle 或 Symfony 的 HttpClient,您可以模拟它以查看请求是否发送一次或多次
  • @cerad 谢谢,这很有希望,但返回错误Error: Call to undefined method Symfony\Bundle\FrameworkBundle\Test\TestContainer::getAlias() 所以我猜这在测试中不受支持。我将使用部分模拟并仅存根该方法

标签: php unit-testing symfony


【解决方案1】:

如何将可调用对象与被测单元隔离开来?

$config = $this->cachePool->get('openid-config', [$this->webScraper, 'getWebContent']);

这样你就可以实现这样的类

class WebScraper
{
    public function getWebContent(ItemInterface $item)
    {
        $item->expiresAfter(self::CACHE_TIME_SECONDS);
        $webContent = file_get_contents($this->openIdConfigurationUrl);
        if (false === $webContent) {
            $message = "Failed to fetch openid config from web at [{$this->openIdConfigurationUrl}]";
            $this->logger->error($message);
            throw new CannotReadOpenIdConfigException($message);
        }
        
        return $webContent;
    }
}

然后可以自行进行单元测试。

这确实意味着您遇到了一个问题;您仍然无法测试是否实际调用了 $this->webScraper->getWebContent。然而,这仍然是向前迈出的一大步。

【讨论】:

    猜你喜欢
    • 2017-07-08
    • 2018-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-20
    • 2018-12-27
    • 2023-03-23
    相关资源
    最近更新 更多