【问题标题】:phpunit test guzzle response is empty objectphpunit 测试 guzzle 响应为空对象
【发布时间】:2021-03-20 16:47:07
【问题描述】:

我有以下测试:

public function it_can_find_by_id(): void
    {
        $oauth = factory( SuperOfficeOAuth::class )->create();
        Auth::login( $oauth->user );
        $content = file_get_contents( __DIR__.'/../_sample-responses/Contact/find.json' );

        Http::fake( [
            'superoffice.com/*' => Http::response( $content, 200, [ 'Content-Type' => 'application/json' ] ),
        ] );

        $contact = ( new Contact )->find(3);

        $this->assertIsObject( $contact );
        $this->assertEquals(3, $contact->contact_id);
    } 

find.json 文件:

{
    "ContactId": 3,
    "Name": "Amadeus AS",
    "Department": "AAvdeling",
    "OrgNr": "",
    "Number1": "AmadeusA",
    "Number2": "AA10011",
    "UpdatedDate": "2006-02-22T09:35:41",
    "CreatedDate": "2002-07-23T16:01:34",
    "Emails": [
        {
            "Value": "qa0@superoffice.com",
            "StrippedValue": "qa0@superoffice.com",
            "Description": "",
            "TableRight": null,
            "FieldProperties": {
            }
        }
    ]
}
class Contact extends Model
{
    public function find(int $id): object
    {
        $this->url .= '/'.$id;
        return parent::get();
    }
}

// There is another class handeling tokens but isn't relevant for the example

class Model extends Client
{ 
    public function get()
    {
        $this->setUrl();

        $this->setHeaders();

        return parent::get();
    }
}

// Client Class

use GuzzleHttp\HandlerStack;
use Psr\Http\Message\StreamInterface;
use Spatie\GuzzleRateLimiterMiddleware\RateLimiterMiddleware;
use GuzzleHttp\Client as GuzzleClient;

class Client
{


    public function __construct()
    {
        $stack = HandlerStack::create();
        $stack->push(RateLimiterMiddleWare::perSecond(10));
        $this->client = new GuzzleClient();
    }

    public function get()
    {
        return (object)json_decode($this->request('GET', $this->url, $this->headers)->getBody());
    }

    private function request(string $method, string $url, ?array $headers = null, ?array $body = null): object
    {
       $response = null;
        try
        {
            $response = $this->client->request($method, $url, [
                'headers' => $headers,
                'body' => json_encode($body)
            ] );
        }
        catch(ClientException $exception)
        {
        }
       
        return $response;
     }
}

因此,在测试和调试联系人 find 方法时,parent::get() 返回 {#742} 但不是来自 find.json 文件的 json 对象。所以我的问题是如何测试/模拟响应以使其返回 json 对象?在生产中,它确实按预期返回了 json 对象。

还尝试将响应模拟如下:

$this->mock(function($mock) use($content) {
            $mock->shouldReceive('request')->andReturns(new Response(200, [], $content));
});

$mock = Mockery::mock(Client::class);
$mock->shouldReceive('request')
     ->andReturn(new Response(200, [], $content));

$this->app->instance(Client::class, $mock);

class TestCase
{
    public function createMockResponse($content, int $status = 200): Response
    {
        $content = utf8_encode($content);
        $response = new Response($status, ['Content-Type' => 'application/json'], json_encode($content));

        $mock = new MockHandler([$response]);

        $handler = HandlerStack::create($mock);
        $client = new Client(['handler' => $handler]);

        $this->app->instance(Client::class, $client);

        return $response;
    }
}

取自here

【问题讨论】:

    标签: laravel phpunit guzzle laravel-7


    【解决方案1】:

    事实证明,最后一个经过测试的模拟示例确实有效。它需要一些改变:

    class TestCase
    {
        public $client;
    
        public function createMockResponse($content, int $status = 200): Response
        {
            $content = utf8_encode($content);
            $response = new Response($status, ['Content-Type' => 'application/json'], json_encode($content));
    
            $mock = new MockHandler([$response]);
    
            $handler = HandlerStack::create($mock);
            $this->client = new Client(['handler' => $handler]);
    
            $this->app->instance(Client::class, $this->client);
    
            return $response;
        }
    }
    

    每个“扩展”类都需要一个类似的结构:

    public function __construct(?GuzzleClient $client = null)
    {
        parent::__construct($client);
    }
    

    在我自己的 Client 类中,可以执行以下操作:

    public function __construct(?GuzzleClient $client = null)
    {
        $stack = HandlerStack::create();
        $stack->push(RateLimiterMiddleWare::perSecond(10));
        $this->client = $client ?? new GuzzleClient();
    }
    

    这样我的Client 就可以使用模拟客户端了。

    (new Contact($this->client))->find(3);
    

    感觉这不是最佳做法,但目前可行。

    【讨论】:

      猜你喜欢
      • 2023-03-10
      • 1970-01-01
      • 2013-11-10
      • 2018-08-28
      • 1970-01-01
      • 2013-06-21
      • 1970-01-01
      • 1970-01-01
      • 2019-02-02
      相关资源
      最近更新 更多