Laravel 控制器测试中的嘲讽误报

Mockery false positive in Laravel controller test

我正在尝试学习如何将 Mockery 与 Laravel 5 一起使用。我的努力主要基于 Way 的书(Laravel 测试解码)和其他教程,其中说 [与 PHPUnit] 集成只需要 tearDown() 方法。所以我把它包括在内。问题是它似乎并没有在测试之间重置东西。我的测试 class 内容基本上是这样的:

public function __construct()
{
    $this->mock = Mockery::mock('Class\To\Mock');
}

public function tearDown()
{
    Mockery::close();
}

public function test_RedirectWithoutAuthentication()
{
    // Act
    $this->call('GET', '/path/1');

    // Assert
    $this->assertRedirectedTo('/auth/login');
}

public function test_X()
{
    // Arrange
    $this->mock->shouldReceive('MockedClassMethod')->once();

    // Act
    $this->call('GET', '/path/1');
}

第一个测试成功,Auth 中间件将用户踢到登录页面。为了 TDD,我在实际编写 MockedClassMethod 之前编写了第二个测试。所以按照我的想法,它应该会失败得很惨。但事实并非如此。它通过了!

如果我改变测试的顺序,它 "works"(未写的失败,auth 通过)这让我相信这不是一个真正的顺序问题,而是与一个测试没有被清理有关先上后下。

任何见解都会避免我剩下的头发被拔掉。 :-)

根据PHPUnit doc

The setUp() and tearDown() template methods are run once for each test method (and on fresh instances) of the test case class.

构造函数仅在第一次被调用,因此在 class 的第二次测试执行之前调用了 tearDown,结果是模拟实例被关闭。

为了解决您的问题,您可以使用初始化模拟对象的设置方法。因此,将测试 class 的 class 构造函数替换为如下设置方法:

尝试使用这个:

protected function setUp() 
{
    $this->mock = Mockery::mock('Class\To\Mock');
}

而不是:

public function __construct()
{
    $this->mock = Mockery::mock('Class\To\Mock');
}

希望对您有所帮助

我曾尝试使用 Matteo 描述的 setUp() 方法,但它导致测试根本无法 运行。所以我放弃了那门课程,以为我离得很远。但是 Matteo 的建议让我重新考虑了它。

深入研究 为什么 它导致测试失败表明 $app 对象从未被创建。嗯...然后我突然意识到 setUp() 方法 overriding 一些重要的东西。所以要修复它,只需要先调用父方法即可!像这样:

public function setUp()
{
    parent::setUp();
    $this->mock = Mockery::mock('Class\To\Mock');
}

从那时起,setUp() 和 tearDown() 按预期工作。

我仍然不确定为什么我找到的所有示例都显示在构造函数中创建的模拟。也许我仍然没有得到什么,但至少它正在工作......目前。 :-)