Mocking GuzzleHttp\Client 用于测试 Lumen 路由
Mocking GuzzleHttp\Client for testing Lumen route
我有一个使用以下两个文件的简单 Lumen 应用程序,在请求根路由 /
时,它会请求使用 GuzzleHttp\Client
获取 URL:
routes/web.php
<?php
$router->get('/', ['uses' => 'MyController@index', 'as' => 'index']);
app/Http/Controllers/MyController
<?php
namespace App\Http\Controllers;
use GuzzleHttp\Client;
use Illuminate\Http\Request;
class MyController extends Controller {
protected $client;
public function __construct() {
$this->client = new Client();
}
public function index( Request $request ) {
$response = $this->client->request( 'get', 'https://www.google.com/' );
return Response()->json( [ 'status' => $response->getStatusCode() ] );
}
}
但是,我想写一个测试,其中 $response->getStatusCode()
将 return 444
,所以我写了下面的测试,试图模拟 getStatusCode()
中的方法 GuzzleHttp\Client
:
<?php
use GuzzleHttp\Client;
class MyTest extends TestCase {
protected $instance;
public function testMyRoute() {
$client = Mockery::mock( Client::class )
->shouldReceive( 'getStatusCode' )
->once()
->andReturn( 444 );
$this->app->instance( Client::class, $client );
$this->json( 'get', '/' )->seeJson( [ 'status' => 444 ] );
}
public function tearDown() {
parent::tearDown();
Mockery::close();
}
}
但是 运行 phpunit
失败了:
~/experiment/lumen-test/testing » phpunit
PHPUnit 5.7.27 by Sebastian Bergmann and contributors.
F 1 / 1 (100%)
Time: 868 ms, Memory: 14.00MB
There was 1 failure:
1) MyTest::testMyRoute
Unable to find JSON fragment ["status":444] within [{"status":200}].
Failed asserting that false is true.
~/experiment/lumen-test/testing/vendor/laravel/lumen-framework/src/Testing/Concerns/MakesHttpRequests.php:288
~/experiment/lumen-test/testing/vendor/laravel/lumen-framework/src/Testing/Concerns/MakesHttpRequests.php:213
~/experiment/lumen-test/testing/tests/MyTest.php:15
FAILURES!
Tests: 1, Assertions: 2, Failures: 1.
说明mocking没有生效。我在这里错过了什么?
编辑-1
根据@sam 的评论 修改 MyController
构造函数后,我将测试修改如下:
use GuzzleHttp\Psr7\Response;
-
public function testMyRoute() {
$response = new Response(444);
$client = Mockery::mock( Client::class )
->makePartial()
->shouldReceive( 'request' )
->once()
->andReturn( $response );
$this->app->instance( Client::class, $client );
$this->json( 'get', '/' )->seeJson( [ 'status' => 444 ] );
}
您正在构造函数中实例化 Client
,这意味着它不会从容器中解析出来。您的控制器应该接受 Client
作为构造函数中的参数,它将通过 Laravel.
从容器中解析出来
public function __construct(Client $client = null) {
$this->client = $client ?: new Client;
}
如果没有提供,这只会创建一个新的 Client
。
https://laravel.com/docs/5.6/container#resolving
Automatic Injection
Alternatively, and importantly, you may "type-hint" the dependency in the constructor of a class that is resolved by the container, including controllers, event listeners, queue jobs, middleware, and more. In practice, this is how most of your objects should be resolved by the container.
我有一个使用以下两个文件的简单 Lumen 应用程序,在请求根路由 /
时,它会请求使用 GuzzleHttp\Client
获取 URL:
routes/web.php
<?php
$router->get('/', ['uses' => 'MyController@index', 'as' => 'index']);
app/Http/Controllers/MyController
<?php
namespace App\Http\Controllers;
use GuzzleHttp\Client;
use Illuminate\Http\Request;
class MyController extends Controller {
protected $client;
public function __construct() {
$this->client = new Client();
}
public function index( Request $request ) {
$response = $this->client->request( 'get', 'https://www.google.com/' );
return Response()->json( [ 'status' => $response->getStatusCode() ] );
}
}
但是,我想写一个测试,其中 $response->getStatusCode()
将 return 444
,所以我写了下面的测试,试图模拟 getStatusCode()
中的方法 GuzzleHttp\Client
:
<?php
use GuzzleHttp\Client;
class MyTest extends TestCase {
protected $instance;
public function testMyRoute() {
$client = Mockery::mock( Client::class )
->shouldReceive( 'getStatusCode' )
->once()
->andReturn( 444 );
$this->app->instance( Client::class, $client );
$this->json( 'get', '/' )->seeJson( [ 'status' => 444 ] );
}
public function tearDown() {
parent::tearDown();
Mockery::close();
}
}
但是 运行 phpunit
失败了:
~/experiment/lumen-test/testing » phpunit
PHPUnit 5.7.27 by Sebastian Bergmann and contributors.
F 1 / 1 (100%)
Time: 868 ms, Memory: 14.00MB
There was 1 failure:
1) MyTest::testMyRoute
Unable to find JSON fragment ["status":444] within [{"status":200}].
Failed asserting that false is true.
~/experiment/lumen-test/testing/vendor/laravel/lumen-framework/src/Testing/Concerns/MakesHttpRequests.php:288
~/experiment/lumen-test/testing/vendor/laravel/lumen-framework/src/Testing/Concerns/MakesHttpRequests.php:213
~/experiment/lumen-test/testing/tests/MyTest.php:15
FAILURES!
Tests: 1, Assertions: 2, Failures: 1.
说明mocking没有生效。我在这里错过了什么?
编辑-1
根据@sam 的评论 MyController
构造函数后,我将测试修改如下:
use GuzzleHttp\Psr7\Response;
-
public function testMyRoute() {
$response = new Response(444);
$client = Mockery::mock( Client::class )
->makePartial()
->shouldReceive( 'request' )
->once()
->andReturn( $response );
$this->app->instance( Client::class, $client );
$this->json( 'get', '/' )->seeJson( [ 'status' => 444 ] );
}
您正在构造函数中实例化 Client
,这意味着它不会从容器中解析出来。您的控制器应该接受 Client
作为构造函数中的参数,它将通过 Laravel.
public function __construct(Client $client = null) {
$this->client = $client ?: new Client;
}
如果没有提供,这只会创建一个新的 Client
。
https://laravel.com/docs/5.6/container#resolving
Automatic Injection
Alternatively, and importantly, you may "type-hint" the dependency in the constructor of a class that is resolved by the container, including controllers, event listeners, queue jobs, middleware, and more. In practice, this is how most of your objects should be resolved by the container.