简体   繁体   English

Laravel模拟与Mockery Eloquent模型

[英]Laravel mock with Mockery Eloquent models

I'm developing a PHP (5.4.25) application with laravel(4.2) framework. 我正在使用laravel(4.2)框架开发PHP(5.4.25)应用程序。 I'd like test my UserController with Mockery , so I've fit my UserController in this way: 我想用Mockery测试我的UserController,所以我以这种方式安装了UserController:

class UsersController extends \BaseController {
    protected $user;

    public function __construct(User $user) {
        $this->user = $user;
        $this->beforeFilter('csrf', array('on'=>'post'));
    }

    public function store() {
        $validator = Validator::make(Input::all(), User::$rules);

        if ( $validator->passes() ) {
            $this->user->username = Input::get('username');
            $this->user->password = Hash::make(Input::get('password'));
            $this->user->first_name = Input::get('first_name');
            $this->user->last_name = Input::get('last_name');
            $this->user->email = Input::get('email');
            $this->user->save();


            return true;
        } else {
            return false;
        }
    }

I want mock Eloquent User model so i develop my UsersControllerTest so: 我想要模拟Eloquent用户模型,所以我开发了UsersControllerTest:

class UsersControllerTest extends TestCase {

    private $mock;

    public function __construct() {}

    public function setUp() {
        parent::setUp();

        $this->createApplication();                                                     
    }

    public function tearDown() {
        parent::tearDown();

        Mockery::close();
    }

    public function testStore() {
        $this->mock = Mockery::mock('Eloquent','User[save]');                                           
        $this->mock
            ->shouldReceive('save')
            ->once()
            ->andReturn('true');                                                        
        $this->app->instance('User', $this->mock);                                      

        $data['username'] = 'qwerety';
        $data['first_name'] = 'asd';
        $data['last_name'] = 'asd123';
        $data['email'] = 'test@gmail.com';
        $data['password'] = 'password';
        $data['password_confirmation'] = 'password';

        $response = $this->call('POST', 'users', $data);

        var_dump($response->getContent());
    }

} 

When I run my test it returns me this error: 当我运行测试时,它会向我返回此错误:

Mockery\Exception\InvalidCountException : Method save() from Mockery_0_User should be called
 exactly 1 times but called 0 times.

Why? 为什么? What's wrong? 怎么了?

EDIT: I found the problem - If I don't use mock object all works fine and the controller create a new user in the DB, but when I use mock the Input:all() method returns empty array. 编辑:我发现了问题-如果我不使用模拟对象,则一切正常,控制器在数据库中创建一个新用户,但是当我使用模拟时, Input:all()方法返回空数组。

-- Thanks - 谢谢

The way you are testing this, in the controller constructor is passed an instance of the real Eloquent model, not the mock. 测试这种方式的方式是,在控制器构造函数中传递真实的Eloquent模型的实例,而不是模拟对象。 If you want to test the facades (as clearly stated in the documentation ) you should call the shouldReceive() method directly on the facade to have it mocked. 如果要测试外观(如文档中明确说明的那样),则应直接在外观上调用shouldReceive()方法以shouldReceive()

But, since you are redefining the $this->user variable in the store() method of the controller, it will not be called, unless you remove the hardcoded instantiation and use the injected $user . 但是,由于您要在控制器的store()方法中重新定义$this->user变量,除非您删除硬编码的实例并使用注入的$user ,否则它将不会被调用。

Edit: i overlooke the $this->app->instance('User', $this->mock); 编辑:我忽略了$this->app->instance('User', $this->mock); line. 线。 So, the problem may be due the fact that in the store method you are getting a new class instance directly, and not via the Laravel IoC container. 因此,问题可能出在以下事实:在store方法中,您直接获得了一个新的类实例,而不是通过Laravel IoC容器。 instead of $this->user = new User; 而不是$this->user = new User; in your store method, you should get it via App::make('User'); 在您的存储方法中,您应该通过App::make('User');获得它App::make('User');

i had this same issue when i started testing..... the thing there is that, in your userscontroller store method you are actually saving the user to the database and base on your code it might work just fine but you are surprise that it is actually failing the test. 当我开始测试时,我遇到了同样的问题.....问题是,在您的userscontroller存储方法中,您实际上是在将用户保存到数据库中,并根据您的代码运行,但效果很好,但您感到惊讶实际上没有通过测试。 Now think of it this way, you mock the user, and you told your test that when ever i call User model, please give me the mock version of my user, like you did in your code line below 现在以这种方式思考,您模拟了用户,并且告诉您测试,无论何时我调用用户模型,都请给我用户的模拟版本,就像您在下面的代码行中所做的那样

$this->app->instance('User', $this->mock);

Now the problem is that you need to also call the mock version of save() method from the through the mock version of User like so: 现在的问题是,您还需要从User的模拟版本开始调用save()方法的模拟版本,如下所示:

$this->mock->save();

Consider the following Example: 考虑以下示例:

public function testStore()
{
    $input = ['name', 'Canaan'];

    $this->mock
        ->shouldReceive('create')
        ->once()->with($input);

    $this->app->instance('User', $this->mock);
    $this->mock->create($input);

    $this->call('POST', 'users', $input);

}

i hope it helps you. 希望对您有帮助。

The problem was in $this->createApplication(); 问题出在$this->createApplication(); .

I have commented that line and Input::all() works fine with all input parameters! 我已经评论了该行,并且Input::all()与所有输入参数都可以正常工作!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM