Как выполнить тестовый контроллер (PHPUnit), который вызывает внешний API - PullRequest
0 голосов
/ 06 февраля 2020

У меня есть 2 файла: MyController. php, APIModel. php

MyController. php

class MyController extends Controller
{
    public function post(Request $request)
    {
        $apiModel = new APIModel;                 
        $apiResponse = $apiModel->GenId();
        // Other process such as get data from database, validate data
        return view(...);
    }
}

APIModel. php

class APIModel extends Model
{
   function GenId()
   {
        $response = $this->callAPI('GET', config('services.api_url.API_URL_GENID'));
   }

   function callAPI($method, $url, $data = array())
   {
       $curl = curl_init();

       ...

       try
       {
            $result = curl_exec($curl);
            if (!$result) {
                throw new ServiceUnavailableHttpException('Could not connect to interface web service.');
            }
       }
       catch (ServiceUnavailableHttpException $e)
       {
           throw $e;
       }
    }
}

Теперь я хочу выполнить тест phpunit для MyController@post

Поскольку он запускает phpunit, при вызове строки кода "$ apiModel-> GenId ()" возникает ошибка

Можно ли создать фиктивный метод для вызова фиктивного метода вместо вызова $ apiModel-> GenId ()?

Я использую Laravel 5.2.45

Пожалуйста помоги мне!

Ответы [ 2 ]

1 голос
/ 06 февраля 2020

Что вы можете сделать, это зарегистрировать ApiModel в контейнере с помощью поставщика услуг.

Для этого создайте нового поставщика услуг - позвоните ему, например, ApiServiceProvider

php artisan make:provider ApiServiceProvider

Я предполагаю, что вы используете экземпляр ApiModel только в нескольких указанных c местах, поэтому откладываете его регистрацию до тех пор, пока он действительно не понадобится.

use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Support\DeferrableProvider;

class ApiServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register(): void
    {
        $this->app->singleton(APIModel::class, function () {
            return new APIModel;
        });
    }

    public function provides(): array
    {
        return [APIModel::class];
    }
}

Теперь обновите ваш пост метод, внедрив в него экземпляр ApiModel в качестве второго аргумента

class MyController extends Controller
{
    public function post(Request $request, APIModel $client)
    {
        $apiResponse = $client->GenId();
        // Other process such as get data from database, validate data
        return view(...);
    }
}

Далее в своем тесте замените привязку на макет ApiModel

$this->mock(APIModel::class, function ($mock) {
    $mock->shouldReceive('GenId')->once()->andReturn(1);
});

Над I Я указываю, что метод GenId должен возвращать 1, но вы можете изменить его на то, что вам нужно.

Подробнее о насмешках: Насмешливые объекты

В качестве альтернативы вы можете просто использовать анонимный класс и заменить экземпляр ApiModel на контейнере на него

$this->instance(APIModel::class, new class {
    public function GenId()
    {
        return 1;
    } 
});

Если вы хотите, чтобы оставшаяся функциональность ApiModel работала полностью и только замените GenId метод, тогда вы можете расширить его

$this->instance(APIModel::class, new class extends ApiModel {
    public function GenId()
    {
        return 1;
    }
});

Надеюсь, это поможет.

0 голосов
/ 06 февраля 2020

добавить use APIModel; выше класса MyController. Нужно быть зарегистрированным псевдонимом или иным образом добавить полный путь к этому классу.

Затем добавьте return $response; в GenId () функцию.

...