Как имитировать вызовы API внутри контроллеров в phpunit / laravel

#phpunit #guzzle #laravel-8

#phpunit #guzzle #laravel-8

Вопрос:

Я создаю модульные тесты в Laravel 8 с помощью phpunit, и у меня есть контроллер, который использует внешний API для получения данных для моих функций с помощью HTTP-клиента Guzzle.

Я поместил метод для вызова guzzle внутри Controller.php , чтобы к нему можно было получить доступ в любом другом контроллере, расширив этот класс

 class Controller extends BaseController
{
    protected function getAPI($url, $params = [])
    {
        $test_api = new Client();
        $headers = [
             'form_params' => $params,
             'http_errors' => false
        ];
            
        $response = $test_api->get($url, $headers);

        // More stuff to get the response...
    }
}
 

На других контроллерах я вызвал метод для выполнения вызова API

 class OtherController extends Controller
{
     public function someMethod()
     {
          $response = $this->getAPI('/get_data', [], 'get');

          // More stuffs...
     }
}
 

Модульный тест, который я создаю, предназначен для someMethod() , и я не знаю, как имитировать вызов API внутри этого контроллера, который был расширен на другом контроллере.

Я хотел имитировать вызов API, поэтому мне не нужно на самом деле «вызывать» API. Я проверил документацию guzzle о тестировании (https://docs.guzzlephp.org/en/stable/testing.html#mock-handler ) но это не имеет смысла в том, как реализовать это в моем сценарии.

Ответ №1:

Вы можете использовать PHPUnit:

 use TestsTestCase;

[...]

public function testApiOtherControllerSomeMethod(){

    //Prepare your sample data that mocks API result
    //or create a variable with your wanted api mocked data.
    $apiTestData = Storage::disk('test-data-api')
        ->get('apiTestData.txt');

    //Using the PHPUnit MockBuilder, target the class and method
    //you want to mock. In your case, you mock the inherited method
    //"getAPI" from Controller, in OtherController
    $apiMock = $this->getMockBuilder(OtherController::class)
        ->onlyMethods(['getAPI'])
        ->getMock();
    
    //use the mock object to change the method's return output
    $apiMock->expects($this->any())
        ->method('getAPI')
        ->willReturn($apiTestData);

    //now the mock object will behave like the OtherController class
    //and you can now call "someMethod", which will return the mocked
    //data when calling getAPI() internally.
    $testResult = $apiMock->someMethod();

    //$this->assert... your returned mocked data.
}
 

В качестве примечания, вам, вероятно, следует перенести обработку API из основного класса контроллера в службу API.