[英]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.