【问题标题】:Laravel mock with Mockery Eloquent models使用 Mockery Eloquent 模型模拟 Laravel
【发布时间】:2014-11-05 02:42:57
【问题描述】:

我正在开发一个带有 laravel(4.2) 框架的 PHP (5.4.25) 应用程序。我想用 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;
        }
    }

我想要模拟 Eloquent User 模型,所以我开发了我的 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());
    }

} 

当我运行我的测试时,它会返回这个错误:

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

为什么?怎么了?

编辑: 我发现了问题 - 如果我不使用模拟对象一切正常,并且控制器在数据库中创建一个新用户,但是当我使用模拟时,Input:all() 方法返回空数组。

-- 谢谢

【问题讨论】:

    标签: php laravel mocking phpunit mockery


    【解决方案1】:

    您测试这个的方式是,在控制器构造函数中传递一个真实 Eloquent 模型的实例,而不是模拟。如果你想测试门面(正如documentation 中明确说明的那样),你应该直接在门面上调用shouldReceive() 方法来模拟它。

    但是,由于您在控制器的store() 方法中重新定义了$this->user 变量,因此不会调用它,除非您删除硬编码的实例化并使用注入的$user。

    编辑:我忽略了$this->app->instance('User', $this->mock); 行。因此,问题可能是由于在 store 方法中您直接获得了一个新的类实例,而不是通过 Laravel IoC 容器。而不是你的 store 方法中的$this->user = new User;,你应该通过App::make('User');得到它

    【讨论】:

    • 在同样的错误中也删除了 store 方法中的新类实例。
    【解决方案2】:

    当我开始测试时,我遇到了同样的问题..... 问题是,在您的 userscontroller 存储方法中,您实际上是将用户保存到数据库并基于您的代码它可能工作得很好,但您会惊讶于它实际上没有通过测试。 现在这样想,你模拟用户,你告诉你的测试,当我调用用户模型时,请给我我的用户的模拟版本,就像你在下面的代码行中所做的那样

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

    现在的问题是,您还需要从 User 的模拟版本调用 save() 方法的模拟版本,如下所示:

    $this->mock->save();
    

    考虑以下示例:

    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);
    
    }
    

    希望对你有帮助。

    【讨论】:

    • 如果我不使用模拟对象,一切正常,控制器在数据库中创建一个新用户,但是当我使用模拟时,Input:all() 方法返回空数组。
    • 在测试类上再次调用$this->mock->create($input) 是否会破坏逻辑。对我来说,我觉得这是在欺骗测试并使其通过控制器测试,这意味着无论控制器(被测试的控制器)是否调用$this->user->save();,测试都将通过
    【解决方案3】:

    问题出在$this->createApplication();。

    我已经评论了那行,Input::all() 可以很好地处理所有输入参数!

    【讨论】:

      猜你喜欢
      • 2016-08-17
      • 2020-05-14
      • 2015-03-12
      • 2015-03-27
      • 2015-12-23
      • 2021-12-23
      • 2022-01-04
      • 2014-05-19
      • 2018-03-26
      相关资源
      最近更新 更多