hyperf / hyperf

🚀 A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.
https://www.hyperf.io
MIT License
6.04k stars 1.18k forks source link

[FEATURE] Better HTTP Client Testing #6889

Open floriankraemer opened 1 week ago

floriankraemer commented 1 week ago

Is your feature request related to a problem? Please describe.

I want to test HTTP responses including headers, status code etc.

Hyperf\TestingClient is currently returning only arrays, the data of the payload:

    public function get(string $uri, array $data = [], array $headers = [])
    {
        $response = $this->request('GET', $uri, [
            'headers' => $headers,
            'query' => $data,
        ]);

        return $this->packer->unpack((string) $response->getBody());
    }

This is not very useful when you test API because you are also interested in the status code and returned headers.

Describe the solution you'd like

The Clients methods should return the response object, not an array.

Describe alternatives you've considered

Maybe provide another client class to not break the current implementation of the HTTP Client?

My current workaround is to extend the Client and overload the request() method to write the response to a field that I can then access. The solution is not ideal, because there is a possibility that I won't get the latest response.

namespace HyperfTest;

use Hyperf\HttpMessage\Server\Response;
use Hyperf\Testing\Client;

use function Hyperf\Coroutine\wait;

class TestClient extends Client
{
    protected ?Response $response = null;

    public function getLastResponse(): Response
    {
        return $this->response;
    }

    public function request(string $method, string $path, array $options = [], ?callable $callable = null)
    {
        $this->response = wait(function () use ($method, $path, $options, $callable) {
            $callable && $callable();
            return $this->execute($this->initRequest($method, $path, $options));
        }, $this->waitTimeout);

        return $this->response;
    }
}

Additional context Add any other context or screenshots about the feature request here.

huangdijia commented 1 week ago

Take a look at this trait: src/testing/src/Concerns/MakesHttpRequests.php

floriankraemer commented 1 week ago

Thanks!

floriankraemer commented 1 week ago

I've changed my test but now it looks like it can't resolve some classes anymore.

Now I'm getting this and I did not change anything else than my test. When testing the endpoint manually I also get a correct response and no error. My own implementation from my initial post doesn't have this problem. There must be some difference in what the Trait does and what my implementation does. :confused: I assume it is something in how the server is instantiated?

string(22) "Internal Server Error."
F[ERROR] Entry "App\Feature\Recommendation\Application\Http\Controller\ItemsController" cannot be resolved: Entry "App\Feature\Recommendation\Application\RecommendationFacade" cannot be resolved: Entry "App\Feature\Recommendation\Domain\Service\RecommendationService" cannot be resolved: Entry "App\Feature\Recommendation\Domain\Repository\RecommendationRepositoryInterface" cannot be resolved: the class is not instantiable
Full definition:
Object[App\Feature\Recommendation\Domain\Repository\RecommendationRepositoryInterface]
Full definition:
Object[App\Feature\Recommendation\Domain\Service\RecommendationService]
Full definition:
Object[App\Feature\Recommendation\Application\RecommendationFacade]
Full definition:
Object[App\Feature\Recommendation\Application\Http\Controller\ItemsController][21] in /opt/www/vendor/hyperf/di/src/Exception/InvalidDefinitionException.php
<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace HyperfTest\Cases\Feature\Recommendation\Application\Http;

use Hyperf\Testing\Concerns\MakesHttpRequests;
use PHPUnit\Framework\TestCase;

/**
 * @group ApiTest
 * @internal
 * @coversNothing
 */
class ItemsApiTest extends TestCase
{
    use MakesHttpRequests;

    public function testAddingItemsSuccessfully()
    {
        $response = $this->post('/items', [
            'items' => [
                [
                    'itemId' => 'item-123',
                    'name' => '123',
                    'properties' => [
                        'category' => 'test',
                    ],
                ],
                [
                    'itemId' => 'item-321',
                    'name' => '321',
                    'properties' => [
                        'category' => 'test',
                    ],
                ],
            ],
        ]);

        var_dump($response->getBody()->getContents());

        $response->assertStatus(200);
        $response->assertExactJson([
            'status' => 'success',
            'data' => null,
        ]);
    }

    public function testAddingItemsFailsValidation()
    {
        $response = $this->post('/items', [
            'items' => [
                [
                    'itemId' => '',
                    'name' => '',
                    'properties' => [
                        'category' => 'test',
                    ],
                ],
                [
                    'properties' => [
                        'category' => 'test',
                    ],
                ],
            ],
        ]);

        $response->assertStatus(400);
        $response->assertExactJson([
            'status' => 'fail',
            'data' => [
                "items.0.itemId" => [
                    "Item ID is required",
                ],
                "items.1.itemId" => [
                    "Item ID is required",
                ],
                "items.0.name" => [
                    "Name is required",
                ],
                "items.1.name" => [
                    "Name is required",
                ],
            ]
        ]);
    }
}
huangdijia commented 1 week ago

extends \Hyperf\Testing\TestCase