Question

I'm very new to testing controllers and I'm running into a problem with a method(). I believe I'm either missing something in my test or my Controller / Repository is designed incorrectly.

The application I'm writing is basically one of those secure "one time" tools. Where you create a note, the system provides you with a URL, once that url is retrieved the note is deleted. I actually have the application written but I am going back to write tests for practice (I know that's backwards).

My Controller:

use OneTimeNote\Repositories\NoteRepositoryInterface as Note;

class NoteController extends \Controller {

protected $note;

public function __construct(Note $note)
{
    $this->note = $note;
}

public function getNote($url_id, $key)
{
    $note = $this->note->find($url_id, $key);

    if (!$note) {
        return \Response::json(array('message' => 'Note not found'), 404);
    }

    $this->note->delete($note->id);

    return \Response::json($note);
}
...

I've injected my Note interface in to my controller and all is well.

My Test

use \Mockery as M;

class OneTimeNoteTest extends TestCase {

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

        $this->mock = $this->mock('OneTimeNote\Repositories\EloquentNoteRepository');
    }

    public function mock($class)
    {
        $mock = M::mock($class);

        $this->app->instance($class, $mock);

        return $mock;
    }

    public function testShouldReturnNoteObj()
    {
        // Should Return Note
        $this->mock->shouldReceive('find')->once()->andReturn('test');
        $note = $this->call('GET', '/note/1234567890abcdefg/1234567890abcdefg');
        $this->assertEquals('test', $note->getContent());
    }

}
...

The error I'm getting

1) OneTimeNoteTest::testShouldReturnNoteObj
ErrorException: Trying to get property of non-object

/Users/andrew/laravel/app/OneTimeNote/Controllers/NoteController.php:24

Line 24 is in reference to this line found in my controller:

$this->note->delete($note->id);

Basically my abstracted repository method delete() obviously can't find $note->id because it really doesn't exist in the testing environment. Should I create a Note within the test and try to actually deleting it? Or would that be something that should be a model test? As you can see I need help, thanks!

----- Update -----

I tried to stub the repository to return a Note object as Dave Marshall mentioned in his answer, however I'm now receiving another error.

1) OneTimeNoteTest::testShouldReturnNoteObj
BadMethodCallException: Method     Mockery_0_OneTimeNote_Repositories_EloquentNoteRepository::delete() does not exist on this mock object

I do have a delete() method in my repository and I know it's working when I test my route in the browser.

public function delete($id)
{
    Note::find($id)->delete();
}
Was it helpful?

Solution 2

Building upon Dave's answer, I was able to figure out what my problem is. I wasn't mocking the delete() method. I didn't understand the need to mock each individual method in my controller that would be called.

I just added this line:

$mock->shouldReceive('delete')->once()->andReturnNull();

Since my delete method is just deleting the note after it is found, I went ahead and mocked it but set it to return null.

OTHER TIPS

You are stubbing the note repository to return a string, PHP is then trying to retrieve the id attribute of a string, hence the error.

You should stub the repository to return a Note object, something like:

$this->mock->shouldReceive('find')->once()->andReturn(new Note());
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top