Amir Yousefi
Amir Yousefi

Reputation: 55

How to mock other class functions in testing controller in Laravel

I am trying to test a controller in Laravel that uses another class as a helper which calls an API and returns the result.

To avoid external API calls, I need to mock this helper.

I tried to mock the class inside the controller and run the test but I didn't get what I expected in mock class.

this is my controller method:

public function A(Request $request){
  $helper = new TheHelper();
  $result = $helper->getResult($request->email);
  if($result){
    return response()->json([
                'success' => true,
                'message' => "result found",
            ], 200);  
  }else{
    return response()->json([
                'success' => false,
                'message' => "no result",
            ], 500);
  }

}

My helper method simply calls an API and returns the result.

class TheHelper
{
    public function getResult($email){
      // some api calls
      return $result;
    }
}

Here is my test:

public function testExample()
    {

        $helperMock = Mockery::mock(TheHelper::class);

        // Set expectations
        $helperMock ->shouldReceive('getResult')
            ->once()
            ->with('[email protected]')
            ->andReturn([
                'id' => '100'
            ]);

        $this->app->instance(TheHelper::class, $helperMock);

        $this->json(
            'POST',
            '/api/test_method',
            ['email' => '[email protected]'])
            ->assertStatus(200);
}

My mock function never called. it only checks with the real API inside TheHelper method

Upvotes: 0

Views: 2446

Answers (1)

patricus
patricus

Reputation: 62228

Your test is creating a mock object and binding that mock object into the Laravel service container. However, your controller is not pulling a TheHelper instance from the Laravel service container; it is manually instantiating it with the new keyword. Using the new keyword is core PHP, and does not involve Laravel at all.

Your test is showing you an issue in your code. TheHelper is a dependency of your method, and should therefore be passed into the method instead of being created inside the method.

You either need to update your controller method to use dependency injection, so that Laravel can automatically resolve the TheHelper dependency from its container, or you need to replace your new keyword with a call into the Laravel container.

Using dependency injection:

public function A(Request $request, TheHelper $helper)
{
    $result = $helper->getResult($request->email);
    // rest of function...
}

Manually pull from the container:

public function A(Request $request)
{
    $helper = app(TheHelper::class);
    $result = $helper->getResult($request->email);
    // rest of function...
}

Upvotes: 5

Related Questions