如何使 Mockery 过载选项在 Laravel 5 上正常工作

How to make Mockery overload option work properly on Laravel 5

我正在尝试在 Laravel 5 上使用 Mockery 库的 overload 选项。

我现在的环境:

我写了这个测试用例:

namespace Tests\Unit;

use Mockery;
use Tests\TestCase;

/**
 * @runTestsInSeparateProcesses
 * @preserveGlobalState disabled
 */
class RenewSignatureTest extends TestCase
{
    public function testHandle()
    {
        $mock = Mockery::mock('overload:App\FooClass');

        $mock->shouldReceive('callBar')
            ->times(2);
    }
}

根据documentation,这个测试应该会失败,但不管我做什么,测试永远不会失败!它总是导致:

Time: 304 ms, Memory: 19.53 MB

OK (1 test, 1 assertion)

如果我删除 overload: 选项,测试将失败。所以我假设我没有按预期使用库的方法。

新测试:

namespace Tests\Unit;

use Mockery;
use Tests\TestCase;

/**
 * @runTestsInSeparateProcesses
 * @preserveGlobalState disabled
 */
class RenewSignatureTest extends TestCase
{
    public function testHandle()
    {
        $mock = Mockery::mock('App\FooClass');

        $mock->shouldReceive('callBar')
            ->times(2);
    }
}

结果:

Mockery\Exception\InvalidCountException: Method callBar(<Any Arguments>) from Mockery_0__App_FooClass should be called exactly 2 times but called 0 times.

我做错了什么吗?有谁知道如何正确使用这个选项?

阅读页面,我认为这就是您要查找的错误:

When Mockery overloads a class, because of how PHP works with files, that overloaded class file must not be included otherwise Mockery will throw a “class already exists” exception. This is where autoloading kicks in and makes our job a lot easier.

如果您从测试中删除这两行,将会导致您正在寻找的错误,它们被添加到手册页的第二个代码示例和第三个示例中的代码中:

 * @runTestsInSeparateProcesses
 * @preserveGlobalState disabled

这意味着您的代码不会利用 psr4 自动加载器或任何现有的自动加载器,并且会以牺牲速度为代价为您创建一个新的自动加载器,因为它不会使用您转储的 classmap 并且必须从头开始构建它。

如果你去掉上面的两行,你会得到预期的错误,因为它会尝试用同名的 class 使你的 class 过载。 class 已经自动加载,所以你会得到一个致命错误。

因此,如果您想阻止对 callBar 和 return void 的调用,这就是您的代码将要执行的操作,这是正确的。

删除 overload 将意味着您的模拟不再有效,因为您必须通过构造函数传递它才能使其工作。

更新:

根据你的更新,我可以得出结论,你的代码必须是 运行 模拟的 callBar 方法两次(不是实际的 callBar 方法),你的模拟 fooBar class 使用 overload。当模拟方法被调用时,真正的 callBar 方法内部什么都没有发生,它只是注册它被调用了。例如,如果您期望它一次,请编写 shouldReceive(1) 然后修复您的测试运行的代码。

当您删除 overload 时,全局注入不会发生,因此您的模拟永远不会被注入。但是,您在 mock class 上的 mock callBar 方法仍然期望 运行 两次,因此您会收到错误消息。您需要从测试中完全删除 2 行模拟代码。

保留 @ 语句,因为它有助于防止上述 psr4 错误。

这不是测试的方法,你不应该使用 overload: 选项... Laravel 可以帮助你做很多事情,不要再造轮子或尝试这样做。 ..

为什么需要使用 @runTestsInSeparateProcesses@preserveGlobalState disabled


假设你的测试是这样的:

namespace Tests\Unit;

use App\FooClass;
use App\Service\ServiceForTesting;
use Mockery;
use Tests\TestCase;

class RenewSignatureTest extends TestCase
{
    public function testHandle()
    {
        $mock = Mockery::mock(FooClass::class);

        $mock->shouldReceive('callBar')
            ->times(2);

        $myClass = app(ServiceForTesting::class);
        $myClass->run($mock);
        $myClass->run($mock);
    }
}

你应该有这样的代码:

namespace App;

class FooClass
{
    public function callBar()
    {
        return 'Works !!!';
    }
}

现在,假设你有一个独立的 class(没有控制器或类似的东西,你正在进行单元测试),你应该有这样的东西:

namespace App\Service;

use App\FooClass;

class ServiceForTesting
{
    public function run(FooClass $class)
    {
        return $class->callBar();
    }
}