Reputation: 455
I have the a simple Lumen application using the following two files, that upon requesting the root route /
it makes a request to get a URL using GuzzleHttp\Client
:
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() ] );
}
}
However, I want to write a test in which $response->getStatusCode()
will return 444
, so I wrote the following test, trying to mock getStatusCode()
method in 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();
}
}
But running phpunit
fails:
~/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.
That indicates that mocking did not take any effect. What am I missing here?
After modifying MyController
constructor as per @sam's comment Mocking GuzzleHttp\Client for testing Lumen route, I modified the test to be as follows:
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 ] );
}
Upvotes: 1
Views: 2293
Reputation: 5599
You're instantiating the Client
in your constructor which means that it's not being resolved out of the container. Your controller should accept the Client
as a parameter in the constructor, which will be resolved out of the container by Laravel.
public function __construct(Client $client = null) {
$this->client = $client ?: new Client;
}
This will only create a new Client
if one has not been provided.
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.
Upvotes: 3