Reputation: 3
I have got 2 files: MyController.php, APIModel.php
MyController.php
class MyController extends Controller
{
public function post(Request $request)
{
$apiModel = new APIModel;
$apiResponse = $apiModel->GenId();
// Other process such as get data from database, validate data
return view(...);
}
}
APIModel.php
class APIModel extends Model
{
function GenId()
{
$response = $this->callAPI('GET', config('services.api_url.API_URL_GENID'));
}
function callAPI($method, $url, $data = array())
{
$curl = curl_init();
...
try
{
$result = curl_exec($curl);
if (!$result) {
throw new ServiceUnavailableHttpException('Could not connect to interface web service.');
}
}
catch (ServiceUnavailableHttpException $e)
{
throw $e;
}
}
}
Now I want to perform a phpunit test for MyController@post
Because it is running phpunit, when calling to the code line "$apiModel->GenId()", the error occurs
Is it possible to create a dummy method to call a dummy method instead of calling $apiModel->GenId()?
I'm using Laravel 5.2.45
Please help me!
Upvotes: 0
Views: 1535
Reputation: 6045
What you could do is to register ApiModel
in the container by using service provider.
To do it, create a new service provider - call it for instance ApiServiceProvider
php artisan make:provider ApiServiceProvider
I'm going to assume you only use the ApiModel
instance in a few specific places, therefore will defer its registration until it's actually needed.
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Support\DeferrableProvider;
class ApiServiceProvider extends ServiceProvider implements DeferrableProvider
{
public function register(): void
{
$this->app->singleton(APIModel::class, function () {
return new APIModel;
});
}
public function provides(): array
{
return [APIModel::class];
}
}
Now, update your post method by injecting instance of ApiModel
to it as a second argument
class MyController extends Controller
{
public function post(Request $request, APIModel $client)
{
$apiResponse = $client->GenId();
// Other process such as get data from database, validate data
return view(...);
}
}
Next, in your test replace the binding with a mock of the ApiModel
$this->mock(APIModel::class, function ($mock) {
$mock->shouldReceive('GenId')->once()->andReturn(1);
});
Above I'm specifying that method GenId
should return 1
, but you can change it to whatever you need it to be.
More on mocking: Mocking Objects
Alternatively you could simply use anonymous class and replace the instance of the ApiModel
on the container with it
$this->instance(APIModel::class, new class {
public function GenId()
{
return 1;
}
});
If you'd like the remaining functionality of the ApiModel
to be fully working and only replace GenId
method then you could extend it
$this->instance(APIModel::class, new class extends ApiModel {
public function GenId()
{
return 1;
}
});
Hope this helps.
Upvotes: 1
Reputation: 281
add use APIModel;
above MyController class. Need to be a registered alias or otherwise add the full path of this class.
Then, add a return $response;
in GenId() function.
Upvotes: 0