簡體   English   中英

使用PHPUnit對Laravel控制器內部進行單元測試

[英]Unit Testing Guzzle inside of Laravel Controller with PHPUnit

我不太確定在這種情況下采用單元測試的方法。 沒有單元測試Guzzle的例子對我來說在這種情況下如何實現是非常有意義的,或者我可能只是錯誤地一起看它。

設置:Laravel 4.2 REST API - 控制器方法在方法中使用Guzzle從另一個api請求數據,如下所示:

<?php

class Widgets extends Controller {
    public function index(){
        // Stuff

        $client = new GuzzleHttp\Client();
        $url = "api.example.com";

        $response = $client->request('POST', $url, ['body' => array(...)]);

        // More stuff
    }
}

?>

我以為我可以按照以下方式進行單元測試,一切都會正常工作。

function testGetAllWidgets(){
    $mock_response = array('foo' => 'bar');

    $mock = new MockHandler([
        new Response(200, $mock_response),
    ]);

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

    $response = $this->call('GET', '/widgets');

    // Do asserts, etc.
}

但是,Guzzle仍在向外部服務發出實際的HTTP請求。 我的猜測可能是在Controller方法中設置客戶端創建以使用$ handler,但我無法想象這是正確的方法。 我錯過了什么?

編輯我的解決方案最終如下:

這個解決方案感覺最正確,而且是Laravel方式。 參見IoC容器

我會在每個api調用上面添加這個(根據在api調用中需要模擬多少外部調用來更改模擬響應)。

$this->app->bind('MyController', function($app){
    $response_200 = json_encode(array("status" => "successful"));
    $response_300 = json_encode("MULTIPLE_CHOICES");

    $mock = new MockHandler([
        new Response(200, [], $response_200),
        new Response(300, [], $response_300)
    ]);

    $handler = HandlerStack::create($mock);

    return new MyController(new Client(['handler' => $handler]));
});

$params = array();

$response = $this->call('PUT', '/my-route', $params);

如果控制器需要Guzzle客戶端,我將其添加到控制器:

public function __construct(GuzzleHttp\Client $client)
{
    $this->client = $client;
}

然后將使用$ this-> client進行所有api調用。

對此的“經典TDD”回應是你不應該對Guzzle進行單元測試。 Guzzle是一個第三方庫,應該由自己的開發人員完全測試(並且)。

您需要測試的是您的代碼是否正確調用Guzzle,而不是Guzzle是否在代碼調用時工作。

這樣做的方法如下:

您應該使用依賴注入將Guzzle對象傳遞到控制器中,而不是在控制器中執行new Guzzle() 幸運的是,Laravel讓這很容易; 你需要做的就是為你的控制器類提供一個構造函數方法,並將一個Guzzle對象定義為它的一個參數。 Laravel將完成剩余的創建對象並將其傳遞給您。 然后,構造函數可以將其復制到類屬性,以便其他方法可以使用它。

你的班級現在應該是這樣的:

class Widgets extends Controller {
    private $guzzle;
    public function __construct(GuzzleHttp\Client $guzzle)
    {
        $this->guzzle = $guzzle;
    }

    public function index(){
        // Stuff

        $url = "api.example.com";

        $response = $this->guzzle->request('POST', $url, ['body' => array(...)]);

        // More stuff
    }
}

現在你的測試應該更容易編寫。 您可以在測試時將模擬Guzzle對象傳遞到您的類中。

現在,您可以只觀看您的模擬類,以確保對它的調用與Guzzle API為了撥打電話而預期接收的內容相匹配。

如果你的班級的其余部分取決於從Guzzle收到的輸出,那么你也可以在你的模擬中定義它。

使用https://github.com/php-vcr/php-vcr包。 它有助於記錄和重放HTTP請求。 通過Guzzle測試api調用非常方便

如果有人在努力解決這個問題,那么我找到了替換:

$this->app->bind('MyController', function($app){

$this->app->bind(MyController::class, function($app){

在Laravel 5.5.44中為我做了訣竅

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM