集成测试模拟外墙与注入模拟

myo*_*yol 15 php testing integration-testing laravel

我们有一些传统的laravel项目,它们在课堂上使用外墙.

use Cache;

LegacyClass
{
    public function cacheFunctionOne()
    {
         $result = Cache::someFunction('parameter');

         // logic to manipulate result

         return $result;
    }

    public function cacheFunctionTwo()
    {
         $result = Cache::someFunction('parameter');

         // different logic to manipulate result

         return $result;
    }
}
Run Code Online (Sandbox Code Playgroud)

我们最近的项目使用依赖注入外墙所代表的层级类,正如Taylor Otwell本人暗示的那样.(我们对每个类使用构造函数注入,但为了保持示例简短,这里我使用方法注入并使用单个类.)

use Illuminate\Cache\Repository as Cache;

ModernClass
{
    public function cacheFunctionOne(Cache $cache)
    {
         $result = $cache->someFunction('parameter');

         // logic to manipulate result

         return $result;
    }

    public function cacheFunctionTwo(Cache $cache)
    {
         $result = $cache->someFunction('parameter');

         // different logic to manipulate result

         return $result;
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道外墙可以被嘲笑

public function testExample()
{
    Cache::shouldReceive('get')
                ->once()
                ->with('key')
                ->andReturn('value');

    $this->visit('/users')->see('value');
}
Run Code Online (Sandbox Code Playgroud)

这适用于单元测试.我试图理解的问题是,这些外墙是否被"全球性"嘲弄.

例如,让我们想象一下我写的集成测试(测试一些相互关联的类别而嘲讽的服务-而不是目的使用Live服务结束测试),这在某些时候,执行两个独立的类包含调用同样的方法相同门面具有相同的参数.

在这些被调用的类之间,有一些复杂的功能可以使用相同的参数更改该Facade方法返回的数据.*

$modernClass->cacheFunctionOne($cache); // easily mocked

// logic that changes data returned by laravel Cache object function 'someFunction'

$modernClass->cacheFunctionTwo($cache); // easily mocked with a different mock
Run Code Online (Sandbox Code Playgroud)

我们的现代类很容易测试,因为facade表示的底层类被注入到每个类中(在本例中,每个方法).这意味着我可以创建两个单独的模拟并将它们注入每个类(方法)以模拟不同的结果.

$legacyClass->cacheFunctionOne();

// logic that changes data returned by laravel Cache object function 'someFunction'

$legacyClass->cacheFunctionTwo();
Run Code Online (Sandbox Code Playgroud)

但是在遗留系统中,似乎模拟的外观是"全局的",因此当在每个类中运行外观时,将返回完全相同的值.

我在想这个是正确的吗?

*我理解这个例子从代码架构和测试的角度来看似乎完全是多余的,但我正在剥离所有真正的功能,尝试给出一些我所要求的"简单"示例.

kdv*_*dvy 7

依赖注入与外观

依赖注入的一个主要好处是,一旦开始将依赖项注入方法而不是在方法中实例化/硬编码它们,代码就会变得更加可测试.这是因为您可以从单元测试内部传入依赖项,它们将通过代码传播.

请参阅:http://slashnode.com/dependency-injection/

依赖注入与Facades形成鲜明对比.Facade是静态全局类,PHP语言不允许在静态类上覆盖或替换静态函数.Laravel外墙使用Mockery提供模拟功能,并且它们受到与上述相同的事实的限制.

集成测试的问题可能出现在您希望从非模拟缓存中检索数据的地方,但是一旦您使用Facade :: shouldReceive(),那么Facade :: get()将被模拟的Cache覆盖.反之亦然.因此,Facades不适用于交换模拟和未模拟数据的调用.

为了使用您需要的不同数据集测试代码,最佳做法是重构遗留代码以使用DI.

集成测试

方法更简单

另一种方法是在集成测试开始时调用多个Facade :: shouldReceive().确保您在集成测试中为每个呼叫以正确的顺序获得正确数量的期望.考虑到现有的代码库,这可能是编写测试的更快捷方式.

更难的方法

虽然依赖注入是编程最佳实践.很可能你的代码库有这么多遗留类,重构需要不可思议的时间.在这种情况下,考虑使用带有夹具的测试数据库进行端到端集成测试可能是值得的.

附录: