2016-09-16 15 views
0

私はGuzzleの非同期要求を使用しており、今すぐテストしたいサービスに実装しています。 、PhpUnitとProphecyで引数として呼び出し可能なメソッドをテストする方法

私の方法は、この(擬似、それは100%有効ではない場合は、お許し下さいので)

public function getPlayer(string $uiid, array &$player = []) 
{ 
    $options['query'] = ['id' => $uiid]; 

    $promise = $this->requestAsync('GET', $this->endpoint, $options); 
    $promise->then(function (ResponseInterface $response) use (&$player) { 
     $player = $response->getBody()->getContents(); 
    }); 

    return $players; 
} 

のように見える今、私はそれをテストしたいが、私は実際に呼び出し可能に模擬する方法がわかりません私は常にエラー

1) tzfrs\PlayerBundle\Tests\Api\Player\PlayerServiceTest::testGetPlayer Prophecy\Exception\InvalidArgumentException: Expected callable or instance of PromiseInterface, but got object.

を取得していますので、これは、私はそれが現在

/** @var ObjectProphecy|PromiseInterface $response */ 
$promise = $this->prophesize(PromiseInterface::class); 

$promise->then()->will($this->returnCallback(function (ResponseInterface $response) use (&$player){})); 
01を実装している方法です

動作しませんでした。そして、この

$this->returnCallback(function (ResponseInterface $response) use (&$player){})

はどちらか動作しませんでした。同じエラー。単に

$promise->then(function(){});

ダミーのコールバックをしようとしたとき、私はさえ->reveal()は最初の約束をINGの後、エラーError: Call to a member function then() on stringを取得します。何か案は?

答えて

1

あなたのクラスにプロセッサを挿入して呼び出し可能と呼んでいます。それをチェックアウト、残りは非常に明白です:

public function __construct(Processor $processor) { 
    $this->processor = $processor; 
} 

public function getPlayer(string $uiid, array &$player = []) 
{ 
    $options['query'] = ['id' => $uiid]; 

    $promise = $this->requestAsync('GET', $this->endpoint, $options); 
    $promise->then([$this->processor, "processResponse"]); 

    $player = $this->processor->getPlayer(); 

    return $players; 
} 

とプロセッサ:

class Processor { 

    private $player;   

    public function processResponse (ResponseInterface $response) { 
     $this->player = $response->getBody()->getContents(); 
    } 

    public function getPlayer() { return $this->player;} 
} 
+0

これが見えますか?私はそれをやりたいと思っていません。私のプロジェクトを変えれば、テストはうまくいくでしょう。何とか呼び出し元を模倣する別の方法はありませんか? – Musterknabe

+0

いいえ、そうではありません。それは、単一の責任であるソリッドの原理(それはラヴァレルの重要な原則の1つです)に従う新しいクラスを作ります。現在の実装では、1つのクラスで2つの関数を作成し、応答を送信して解析することを想定しています。 SOLIDを使用することのボーナスの1つとして、テスト可能なコードが得られます。 –

+0

有効なポイント。しかし、Laravelを使用していませんが、Symfonyを使用しています。もう一つは、すでに私は読書とライティングを分けているということです。読み取りは別の場所で行われますが、実際にはstackoverflowの質問の機能は変更されないため、まとめておく必要があります。 しかし、あなたのように実装していて、呼び出し可能ではなく配列経由でメソッドを呼び出すと、テストにどのような影響がありますか?私はまだコールバックを渡さなければならない 'then'関数をモックする必要があります - 編集:私はaproxに行く必要があります。 1時間。あなたが答えたら、私は後で答えるでしょう – Musterknabe

1

私は別の考えを持っていました。

あなたが今作ったものを作る依存関係を作りましょう。requestAsync(); そしてそれをもう一つの模擬約束を返すモックを作りなさい。

class PromiseMock 
{ 
    private $response; 

    public function __construct(ResponseInterface $response) 
    { 
     $this->response = $response; 
    } 

    public function then($callable) 
    { 
     $callable($this->response); 
    } 
} 

テストは

public function testGetPlayer() 
{ 
    $response = new Response(200, [], "Your test response"); 
    $promiseMock = new PromiseMock($response); 

    $mockDependency = $this->getMockBuilder('YourDependencyClass') 
       ->getMock() 
       ->expects("requestAsync")->willReturn($promiseMock); 

    $service = new YouServiceClass($mockDependency); 

    $service->getPlayer("76245914-d56d-4bac-8419-9e409f43e777"); 
} 

のように見え、私は右、単に私のサービスをテストするための新しいクラスを作成しなければならないようなあなたのクラスの変更にのみ

$promise = $this->someNameService->requestAsync('GET', $this->endpoint, $options); 
+0

ちょっと。ご回答有難うございます。私はこの方が良いと思っていますが、それでもコードをあまり変更しないで、 'then'関数はテストをするためにpolyfillのように見えます。 :/。別のクラスを作成せずに直接呼び出し可能コードを直接模倣する方法はありませんか? – Musterknabe

+0

しかし、それは一般的にモックのやり方です。私は別の方法があるとは思わない。 –

+0

申し訳ありませんが、私はばかです。私はそれが「PromiseMock」だとは思わなかった。私はまだそれが 'Processor'だと思った。私はそれを試してみます – Musterknabe

関連する問題