mockery->shouldReceive() 啥时候不应该通过?

Posted

技术标签:

【中文标题】mockery->shouldReceive() 啥时候不应该通过?【英文标题】:mockery->shouldReceive() passing when it shouldnt?mockery->shouldReceive() 什么时候不应该通过? 【发布时间】:2013-12-30 03:04:36 【问题描述】:

我正在使用 phpunit 和 mockery 在 laravel 中学习单元测试。我目前正在尝试测试 UsersController::store()。

我正在模拟用户模型并使用它来测试索引方法,这似乎有效。当我取出 $this->user->all() 测试失败并且它通过时。

在测试 store 方法时,虽然我使用模拟来测试用户模型是否收到 validate() 一次。 store 方法为空,但测试通过。为简洁起见,我省略了课程中不相关的部分

<?php

class UsersController extends BaseController 

    public function __construct(User $user)
    
        $this->user = $user;
    
    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index()
    
        $users = $this->user->all();

        return View::make('users.index')
        ->with('users', $users);
    

    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function create()
    
        return View::make('users.create');
    

    /**
     * Store a newly created resource in storage.
     *
     * @return Response
     */
    public function store()
    
        //
    


UserControllerTest.php

<?php
    use Mockery as m;
class UserControllerTest extends TestCase 

    public function __construct()
    
        $this->mock = m::mock('BaseModel', 'User');
    

    public function tearDown()
    
        m::close();
    

    public function testIndex()
    
        $this->mock
            ->shouldReceive('all')
            ->once()
            ->andReturn('All Users');
        $this->app->instance('User', $this->mock);
        $this->call('GET', 'users');
        $this->assertViewHas('users', 'All Users');
    

    public function testCreate()
    
        View::shouldReceive('make')->once();
        $this->call('GET', 'users/create');
        $this->assertResponseOk();
    

    public function testStore()
    

        $this->mock
            ->shouldReceive('validate')
            ->once()
            ->andReturn(m::mock(['passes' => 'true']));
        $this->app->instance('User', $this->mock);
        $this->call('POST', 'users');
    



【问题讨论】:

【参考方案1】:

默认情况下,Mockery 是一个存根库,而不是一个模拟库(因为它的名称而令人困惑)。

这意味着-&gt;shouldReceive(...) 默认为“零次或多次”。当使用-&gt;once() 时,你说它应该被调用零次或一次,但不能更多。这意味着它总会过去。

当你想断言它被调用一次时,你可以使用-&gt;atLeast()-&gt;times(1)(一次或多次)或-&gt;times(1)(恰好一次)

【讨论】:

感谢您的快速回复。如果我删除对 index() 中的 all 的调用,为什么 testIndex 会失败?我只是在两次测试中将一次()换成了次(1),并且仍然通过了相同的结果。当我在 index() 中删除对 all() 的调用时,testIndex 失败。顺便说一句,在 testindex 中,无论我使用 once() 或 times(1) 的天气如何,嘲弄的 invalidcountexception 都说 all() 应该被准确地调用 1 次,但被调用 0 次。 "->shouldReceive(...)" 仅默认等于“零次或多次”,不影响其他方法。 “->once()”表示应该只调用一次,不调用就失败。【参考方案2】:

要完成Wounter's answer,您必须致电Mockery::close()

此静态调用会清理当前测试使用的 Mockery 容器,并运行您期望所需的任何验证任务。

This 的回答帮助我理解了这个概念。

【讨论】:

【参考方案3】:

您不应该覆盖PHPUnit_Framework_TestCase 的构造函数,使用setUp 进行初始化。另请参阅我对#15051271 和#17504870 的回答

【讨论】:

谢谢你,我认为这成功了。至少 testStore 现在失败了。但是,我的测试扩展了扩展 phpunits 测试用例的测试用例。测试用例有 setUp()parent::setUp(); $this->prepareForTests(); 所以在每个单独的测试类中使用 setUp 会覆盖这个,对吗?还有其他方法吗?我现在只是在每个测试函数中创建一个模拟对象以使其工作。 你类中的setUp方法也需要调用parent::setUp()。这应该是要走的路。

以上是关于mockery->shouldReceive() 啥时候不应该通过?的主要内容,如果未能解决你的问题,请参考以下文章

嘲讽。检查第 100 次调用的参数

嘲弄:如何将 shouldReceive 与 method_exists 一起使用?

当使用 shouldReceive 相同的方法但不同的参数时,嘲笑忘记默认设置

嘲弄“with”方法没有显示失败的原因

在我的测试中不能使用assertViewHas方法

嘲弄“应该接收”但方法不存在