Mock External Library
azieskurniawan opened this issue · 9 comments
Hi Everyone
I want to know how the proper way to Mock External Library. In my case, i want mock external library Guzzle.
This is my controller
<?php
defined('BASEPATH') || exit('No direct script access allowed');
use GuzzleHttp\Client;
class Blabla extends MY_Controller
{
public function guzzle(){
$client = new \GuzzleHttp\Client();
$response = $client->post('blabla.com/authentication',
array (
"headers" => ['Content-Type' => 'application/json'],
"json" => ["username"=>"administrator","password"=>"password"]
)
);
echo $respone->getStatusCode();
}
}
The question is how to write code test to mock and inject external library to controller?
If this case can solved, i can mock other external library.
Thank You.
$client = new \GuzzleHttp\Client();
You can't inject a mock into the $client
.
If you code in the controller constructor like this:
$this->client = new \GuzzleHttp\Client();
You can inject a mock into it with $this->request->setCallable()
.
See https://github.com/kenjis/ci-phpunit-test/blob/master/docs/HowToWriteTests.md#request-and-use-mocks
thank for your response.
I try as you suggest. I change my controller and test code
Controller
<?php
defined('BASEPATH') || exit('No direct script access allowed');
use GuzzleHttp\Client;
class Blabla extends MY_Controller
{
public function __construct()
{
parent::__construct();
$this->client = new \GuzzleHttp\Client();
}
public function guzzle(){
$client = new \GuzzleHttp\Client();
$response = $this->client->post('blabla.com/authentication',
array (
"headers" => ['Content-Type' => 'application/json'],
"json" => ["username"=>"administrator","password"=>"password"]
)
);
echo json_decode($response->getBody())->api_token;
}
}
Test Code
class Gamas_test extends TestCase
{
public function guzzle_test()
{
$this->request->setCallable(
function ($CI){
$mock = new MockHandler([
new Response(200, [], '{ "data": { "api_token": "MOCK TOKEN"}}')
]);
$handlerStack = HandlerStack::create($mock);
$client = new Client(['handler' => $handlerStack]);
$CI->client = $client;
}
);
$output = $this->request('POST', 'gamas/guzzle');
$this->assertContains('MOCK TOKEN',$output);
}
}
my test results:
Failed asserting that 'a475443e0ac47a5d6b047a6f187faf43ac606819d9e1f9e0591b5e6b3fee9f3b' contains "MOCK TOKEN"
but guzzle response not return mock object.
Is there something wrong with my code?
$output = $this->request('POST', 'gamas/guzzle');
blabla/guzzle
?
It seems your code flow is okay. So I don't know what's wrong.
im sorry, the code I posted is wrong. I was write code
$output = $this->request('POST', 'blabla/guzzle');
but still can't inject mock object to controller
I don't know why.
What if you run the following controller and its test?
I changed the code in test code to be like this.
Test Code
class Gamas_test extends TestCase
{
public function guzzle_test()
{
$this->request->setCallable(
function ($CI){
$client = $this->getDouble('\GuzzleHttp\Client', [ 'post' => '{ "data": { "api_token": "MOCK TOKEN"}}' ]);
$this->verifyInvokedOnce($client, 'post');
$CI->client = $client;
}
);
$output = $this->request('POST', 'blabla/guzzle');
$this->assertContains('MOCK TOKEN',$output);
}
}
but still can't inject mock object to controller.
public function guzzle_test()
should be public function test_guzzle()
?
i changed function name to
public function test_guzzle()
still can't inject mock object to controller.
If you still have this problem, feel free to reopen.