1

Following the phpunit documentation, I have come up with the following code. The test fails and the output shows me that it is not calling the stubbed method, but the actual method, hitting the database and returning the data from the database. I believe I am missing a step where I "inject" the test dummy so that it is called instead of the actual class method. Can anyone point out what I am doing wrong here?

My Test :

$shouldReturn = '[{"name":"A Category Name 1"},{"name":"A Category Name 2"},{"name":"A Category Name 3"}]';

// Create a mock for the CategoryClass,
$catClassMock = $this->getMockBuilder(CategoryClass::class)->getMock();

// Set up the Test Dummy for the findAll method and stub what should be returned.
$catClassMock->expects($this->once())
    ->method('findAll')
    ->with($this->returnValue($shouldReturn));

// Setup the controller object, and call the index method.
$CategoriesController = new CategoriesController();
$returnedResults = $CategoriesController->index();

// Assert the results equal what we told the method to return.
$this->assertEquals($returnedResults, $shouldReturn);

CategoriesController method:

public function index() {
    // List all category
    return $this->categoryClass->findAll();
}

Note: $this->categoryClass is being instantiated in the constructor method of CategoriesController. $this->categoryClass = new CategoryClass;

The findAll method of CategoryClass:

public function findAll() {
    // List all categories
    $categories = Category::all(); // Eloquent call to database.
    return json_encode($categories);   
}

Thanks a billion!

2
  • I think you answered the question yourself: "... I am missing a step where I "inject" the test dummy ..." Commented Oct 26, 2016 at 15:36
  • So then I'm on the right path? There isn't any additional steps in the documentation, this is just my analyzing the problem. If I do need to "inject" this stub, how do I go about doing that? This is the documentation I am using: phpunit.de/manual/current/en/… Commented Oct 26, 2016 at 15:43

2 Answers 2

1

When you mock a method in a mocked class object, you have to use that mocked class object to get your your mocked method's response.

So, if you want to have the CategoriesController->index() method call your mocked Categories class instead of the real Categories class, you have to inject the Categories class into the CategoriesController class. Something like this should work:

$shouldReturn = '[{"name":"A Category Name 1"},{"name":"A Category Name 2"},{"name":"A Category Name 3"}]';

$catClassMock = $this->getMockBuilder(CategoryClass::class)
    ->setMethods(['findAll'])
    ->getMock();

// Set up the Test Dummy for the findAll method and stub what should be returned.
$catClassMock
    ->method('findAll')
    ->willReturn($shouldReturn);


// Setup the controller object, and call the index method.
$CategoriesController = new CategoriesController();
$CategoriesController->categoryClass = $catClassMock;
$returnedResults = $CategoriesController->index();

// Assert the results equal what we told the method to return.
$this->assertEquals($returnedResults, $shouldReturn);

I should also mention that creating an in-memory sqlite database that's seeded before every test would also work and take away the need to mock you Eloquent queries. It may also be easier to maintain in the long run. Check out https://laracasts.com/series/phpunit-testing-in-laravel for all the details on how to set up a testing database for Laravel's Eloquent.

Sign up to request clarification or add additional context in comments.

Comments

0

Bind your mocked instance to the class name:

$this->app->instance(CategoryClass::class, $catClassMock);

3 Comments

Thanks for the reply, I was expecting something like this. Unfortunately it isn't working for me. I still get actual database data returned instead of the expected $shouldReturn.
Can you try the updated line instead? I think bind was not the correct way.
Thanks again, I really appreciate your assistance! Still, it isn't working correctly and returning the whole database output.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.