Comment simuler une requête vers une API tierce en utilisant le client GuzzleHttp dans un test fonctionnel Laravel ?
P粉842215006
P粉842215006 2023-11-09 11:42:58
0
1
481

Dans un projet Laravel (Laravel 8 sur PHP 8.0) j'ai un test fonctionnel où les points de terminaison internes sont testés. Le point de terminaison dispose d'un contrôleur qui appelle une méthode sur le service. Le service tente ensuite d'appeler le point de terminaison tiers. C'est ce point de terminaison tiers que je souhaite simuler. La situation actuelle est la suivante :

Tests fonctionnels des points de terminaison internes

public function testStoreInternalEndpointSuccessful(): void { // arrange, params & headers are not important in this problem $params = []; $headers = []; // act $response = $this->json('POST', '/v1/internal-endpoint', $params, $headers); // assert $response->assertResponseStatus(Response::HTTP_OK); }

Contrôleur de point de terminaison interne

class InternalEndpointController extends Controller { public function __construct(protected InternalService $internalService) { } public function store(Request $request): InternalResource { $data = $this.internalService->fetchExternalData(); return new InternalResource($data); // etc. } }

Service interne

use GuzzleHttpClientInterface; class InternalService { public function __construct(protected ClientInterface $client) { } public function fetchExternalData() { $response = $this->httpClient->request('GET', 'v1/external-data'); $body = json_decode($response->getBody()->getContents(), false, 512, JSON_THROW_ON_ERROR); return $body; } }

J'ai regardé la documentation de Guzzle, mais il semble queMockHandlerLa stratégie vous oblige à effectuer des requêtes http dans vos tests, ce qui n'est pas ce que je souhaite dans mes tests. Je souhaite me moquer du client http de Guzzle et renvoyer une réponse http personnalisée que je peux spécifier dans mon test. J'essaie d'émuler le client http de Guzzle comme ceci :

public function testStoreInternalEndpointSuccessful(): void { // arrange, params & headers are not important in this problem $params = []; $headers = []; $mock = new MockHandler([ new GuzzleResponse(200, [], $contactResponse), ]); $handlerStack = HandlerStack::create($mock); $client = new Client(['handler' => $handlerStack]); $mock = Mockery::mock(Client::class); $mock ->shouldReceive('create') ->andReturn($client); // act $response = $this->json('POST', '/v1/internal-endpoint', $params, $headers); // assert $response->assertResponseStatus(Response::HTTP_OK); }

MaisInternalServicecette simulation ne semble pas fonctionner lors des tests.

J'ai aussi réfléchi et essayé d'utiliser Http Fake, mais cela n'a pas fonctionné, je pense que le client http de Guzzle n'étend pas le client http de Laravel.

Quelle est la meilleure façon de résoudre ce problème et de se moquer du point de terminaison tiers ?

Modifier

Inspiré par cette question StackOverflow, j'ai réussi à résoudre ce problème en injectant à un client Guzzle une réponse simulée dans mon service. La différence avec la question StackOverflow ci-dessus est que j'ai dû utiliser$this->app->singleton而不是$this->app->bindcar ma configuration DI était différente :

AppServiceProvider.php

namespace AppProviders; use AppServiceInternalService; use GuzzleHttpClient; use IlluminateSupportServiceProvider; class AppServiceProvider extends ServiceProvider { public function register(): void { // my app uses ->singleton instead of ->bind $this->app->singleton(InternalService::class, function () { return new InternalService(new Client([ 'base_uri' => config('app.internal.base_url'), ])); }); } }


P粉842215006
P粉842215006

répondre à tous (1)
P粉617597173

En fonction de votre injection de dépendances, vous souhaitez utiliser un client http Guzzle personnalisé qui renvoie une réponse simuléebindsingleton化您的InternalService, par exemple comme ceci :

public function testStoreInternalEndpointSuccessful(): void { // depending on your DI configuration, // this could be ->bind or ->singleton $this->app->singleton(InternalService::class, function($app) { $mockResponse = json_encode([ 'data' => [ 'id' => 0, 'name' => 'Jane Doe', 'type' => 'External', 'description' => 'Etc. you know the drill', ] ]); $mock = new GuzzleHttp\Handler\MockHandler([ new GuzzleHttp\Psr7\Response(200, [], $mockResponse), ]); $handlerStack = GuzzleHttp\HandlerStack::create($mock); $client = new GuzzleHttp\Client(['handler' => $handlerStack]); return new InternalService($client); }); // arrange, params & headers are not important in this problem $params = []; $headers = []; // act $response = $this->json('POST', '/v1/internal-endpoint', $params, $headers); // assert $response->assertResponseStatus(Response::HTTP_OK); }

Voir aussi :Tests unitaires dans un contrôleur Laravel à l'aide de PHPUnit

    Derniers téléchargements
    Plus>
    effets Web
    Code source du site Web
    Matériel du site Web
    Modèle frontal
    À propos de nous Clause de non-responsabilité Sitemap
    Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!