Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking Eloquent Models with find()

I am trying to Mock Eloquent Model with Mockery. Model is being injected in Controller via

__construct(Post $model){$this->model=$model}

Now I am calling the find() function in controller

$post = $this->model->find($id);

And here is test for PostsController

class PostsTest extends TestCase{

      protected $mock;

      public function setUp() {
        parent::setUp();
        $this->mock = Mockery::mock('Eloquent', 'Posts'); /*According to Jeffrey Way you have to add Eloquent in this function call to be able to use certain methods from model*/
        $this->app->instance('Posts', $this->mock);
      }

      public function tearDown() {

        Mockery::close();
      }

      public function testGetEdit()
      {
        $this->mock->shouldReceive('find')->with(1)->once()->andReturn(array('id'=>1));

        $this->call('GET', 'admin/posts/edit/1');

        $this->assertViewHas('post', array('id'=>1));
      }
    }

Running PhpUnit gives me error:

Fatal error: Using $this when not in object context in ...\www\l4\vendor\mockery\mockery\library\Mockery\Generator.php(130) : eval()'d code on line 73

This is obviously because find() is declared as static function. Now, the code works without errors, so how can I successfully mock Eloquent model without it failing. Since we are relying on dependency injection, I have to call find() non-statically, otherwise I could just do Post::find().

One solution that I came up with is to create a non-static find() replacement in BaseModel

public function nsFind($id, $columns = array('*'))
{
  return self::find($id, $columns);
}

But this is a big pain as the function has to have different name!

Am I doing something wrong or do you have any better ideas?

like image 343
neyl Avatar asked Jun 09 '13 10:06

neyl


2 Answers

Mocking Eloquent models is a very tricky thing. It's covered in the book, but I specifically note that it's a stop-gap. It's better to use repositories.

However, to answer your question, the issue is that you're not performing the mock within the constructor. That's the only way to get it to work. It's not ideal, and I wouldn't recommend it.

like image 200
JeffreyWay Avatar answered Oct 19 '22 15:10

JeffreyWay


I think that is the reason, Jeffrey introduces Repositories in his book Laravel Testing Decoded (Chapter 10).

Mockery has a section about static methods in its README too, See https://github.com/padraic/mockery#mocking-public-static-methods

like image 2
Felix Avatar answered Oct 19 '22 16:10

Felix