grandadevans's avatar

Best way to unit test model's create method???

Hi all,

I hope someone can help me. This is my first project practising a mixture of TDD/BDD (I'll get to DDD once I've mastered the practice of test first development).

In general it's going great. It's taking considerably longer but I have massive confidence in my code now.

I am now testing the user model and am to the point where I need to unit test the create method. Considering that I do not wan't to touch the extended Eloquent model I am struggling how to separate them. I have tried a few times. Here are the relevant tests.

     public function setUp()
     {
         // the Eloquent object is mocked but no expectations are set on it as yet
         $this->eloquent = m::mock('\Illuminate\Database\Eloquent\Model');

         // Only mock the hasOne; all other methods behave as normal
         $this->user = m::mock('MPC\Models\User[hasOne]');
     }

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

    public function testMakeSureThatUsersCanCreateAccountsOk()
     {
         $this->eloquent
             ->shouldReceive('create')
             ->andReturn('newUserObject');

         assertEquals('newUserObject', $this->user->create([]));
}

And the Model's method

    public static function create(array $attributes = array())
    {
        $user = parent::create($attributes);
//        $user->save();

        return $user;
    }

I gave up on the test first mantra for this one to makra on this one. I hope someone can see what (if anything) I am doing wrong. Thanks in advance John

0 likes
6 replies
grandadevans's avatar

I forgot to add the test results for this test

FATAL ERROR. TESTS NOT FINISHED.
Call to a member function connection() on null 
in /~/www/projects/MPCv4/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2894
[21:09:31] gulp-notify: [Tests Failed!] Your tests failed!
jdubwelch's avatar

I'm not a testing pro, but this video helped me a few months back when I was trying to do something similar. https://laracasts.com/lessons/test-databases-in-memory

Also, if you use Codeception it has a Laravel4 module with a method seeRecord() which will check the database. http://codeception.com/docs/modules/Laravel4#seeRecord. I believe Jeffrey demostrates it in the Larabook Series https://laracasts.com/series/build-a-laravel-app-from-scratch/episodes/7 Video. Here's the tests that uses it: https://github.com/foxted/larabook/blob/master/tests/functional/SignUpCept.php

grandadevans's avatar

Hi @Jdubwelch,

Cheers for taking the time to get all the links together. I have seen the videos and I have reverted to using functional/acceptance testing to confirm the create and store methods work. My next task is to look at AspectMock in the hopes of being able to unit test the methods that way.

I am indeed using codeception but I am using $I->seeInDatabase().

pmall's avatar

@grandadevans I don't understand what you are trying to achieve. You don't have to test Eloquent's create method, you already know it works well.

grandadevans's avatar

Exactly: I want to test all the functionality in my create() without firing the parent::create(). I was hoping (in the above example) that when I mocked Eloquent it would kick in when I called parent::create() but that didn't work.

I did get around this by creating a separate method to do that

public function setParentsCreate(array $attributes = [])
{
    return parent::create($attributes);
}

public static function create(array $attributes = [])
{
    // Any create functionality I have prior to parent::create()
}

Then creating a partial mock on my User object

$this->user partial = m::mock("User[setParentsCreate]")
    ->shouldReceive("setParentsCreate")
    ->andReturn("ARepresentationOfAUserObject");

but then I ran into problems with the create method being static.

I've seen a video this morning showing how to accomplish this with AspectMock so I may need to use this if I insist on unit testing any methods I have in the create method.

pmall's avatar

Why are you defining a create method in your model ?

Please or to participate in this conversation.