Hello, I'm working on an application which will retrieve some data from an external API. I'm using an class called Orders which is resolved via Laravel's Service Container to make the API requests, but I've run into an issue mocking the class in my tests.
The following works as expected.
routes/web.php
Route::get('/orders', function(\App\Orders $orders){
return $orders->getOrders();
});
app\Orders.php
<?php
namespace App;
class Orders
{
public function getOrders()
{
return [
[
'id' => 123
]
];
}
}
tests/Feature/OrderTest.php
<?php
namespace Tests\Feature;
use App\Orders;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class OrderTest extends TestCase
{
use RefreshDatabase;
public function test_orders()
{
$this->mock(Orders::class, function($mock){
$mock->shouldReceive('getOrders')->andReturn([
[
'id' => 123,
],
[
'id' => 456,
],
]);
});
$response = $this->get('/orders');
$response->assertStatus(200)->assertJson([
[
'id' => 123,
],
[
'id' => 456,
],
]);
}
}
But my app will have many Shops, each will have their own orders which will be retrieved from a different API base URL. So I want to be able to resolve the object from the Service Container but pass in a GuzzleHttp\Client based on the shop. So when I make the following changes the app\Orders object is no longer being mocked.
routes/web.php
Route::get('/orders', function(){
$orders = app()->make(\App\Orders::class, ['client' => new \GuzzleHttp\Client()]);
return $orders->getOrders();
});
app\Orders.php
<?php
namespace App;
use GuzzleHttp\Client;
class Orders
{
private $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function getOrders()
{
return [
[
'id' => 123
]
];
}
}
app\Providers\AppServiceProvider.php
<?php
namespace App\Providers;
use App\Orders;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
$this->app->bind(Orders::class, function($app, $args){
return new Orders($args['client']);
});
}
}
I can't find any examples of something similar, so I'm probably not resolving the object correctly from the Service Container, but I can't think of any way to better structure this code. Can anyone help?