14/01/2017 - BEHAT, SYMFONY
In this example we're going to call mock Guzzle client class in test
environment so that we don't call external APIs while running tests.
When we use our application, AppBundle\Util\ClientHelper
is used for dev
and prod
environments while AppBundle\Features\Mock\ClientHelperMock
is used for test
environment.
parameters:
client_helper_class: AppBundle\Util\ClientHelper
parameters:
client_helper_class: AppBundle\Features\Mock\ClientHelperMock
namespace AppBundle\Service;
use AppBundle\Util\ClientHelper;
use Symfony\Component\HttpFoundation\Request;
class PostcodeService
{
private $client;
private $apiUri;
public function __construct(
ClientHelper $client,
$apiUri
) {
$this->client = $client;
$this->apiUri = $apiUri;
}
public function get($postcode)
{
return $this->client->request(Request::METHOD_GET, $this->apiUri.$postcode);
}
}
service:
app.service.postcode:
class: AppBundle\Service\PostcodeService
arguments:
- "@app.util.client_helper"
- "%postcodes_api%"
namespace AppBundle\Util;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\Stream;
class ClientHelper
{
private $client;
public function __construct(ClientInterface $client)
{
$this->client = $client;
}
public function request($method, $uri, array $options = [])
{
$details = null;
try {
/** @var Response $response */
$response = $this->client->request($method, $uri, $options);
/** @var Stream $body */
$body = $response->getBody();
$details = $body->getContents();
} catch (ClientException $e) {
}
return $details;
}
}
services:
app.util.client_helper:
class: '%client_helper_class%'
arguments:
- '@app.util.guzzle'
app.util.guzzle:
class: GuzzleHttp\Client
namespace AppBundle\Features\Mock;
use AppBundle\Util\ClientHelper;
class ClientHelperMock extends ClientHelper
{
public static $data;
public function request($method, $uri, array $options = [])
{
$response = [];
$position = strrpos($uri, '/');
if ($position !== false) {
$postcode = substr($uri, $position+1);
if (isset(self::$data['postcode']) && self::$data['postcode'] == $postcode) {
$response = self::$data['result'];
}
}
return json_encode($response);
}
}
/**
* @param PyStringNode $stringNode
*
* @Given /^the Postcode API is available with data:$/
*/
public function thePostcodeApiIsAvailableWith(PyStringNode $stringNode)
{
ClientHelperMock::$data = json_decode($stringNode->getRaw(), true);
}
Feature: Getting postcode details.
In order to get postcode details
As a user
I should be able call call external API
Scenario: I get empty result for non-existent postcode.
Given the Postcode API is available with data:
"""
{"postcode":"POSTCODE 1","result":{"longitude":-0.11111111,"latitude":0.11111111}}
"""
When I send a "GET" request to "/postcodes/NON-EXISTENT POSTCODE"
Then the response status code should be 200
And the response should contain json:
"""
[]
"""
Scenario: I get full result for existent postcode.
Given the Postcode API is available with data:
"""
{"postcode":"POSTCODE 1","result":{"longitude":-0.11111111,"latitude":0.11111111}}
"""
When I send a "GET" request to "/postcodes/POSTCODE 1"
Then the response status code should be 200
And the response should contain json:
"""
{"longitude":-0.11111111,"latitude":0.11111111}
"""
$ vendor/bin/behat --suite=app src/AppBundle/Features/Postcode.feature
Feature: Getting postcode details.
In order to get postcode details
As a user
I should be able call call external API
Scenario: I get empty result for non-existent postcode.
Given the Postcode API is available with data:
"""
{"postcode":"POSTCODE 1","result":{"longitude":-0.11111111,"latitude":0.11111111}}
"""
When I send a "GET" request to "/postcodes/NON-EXISTENT POSTCODE"
Then the response status code should be 200
And the response should contain json:
"""
[]
"""
Scenario: I get full result for existent postcode.
Given the Postcode API is available with data:
"""
{"postcode":"POSTCODE 1","result":{"longitude":-0.11111111,"latitude":0.11111111}}
"""
When I send a "GET" request to "/postcodes/POSTCODE 1"
Then the response status code should be 200
And the response should contain json:
"""
{"longitude":-0.11111111,"latitude":0.11111111}
"""
2 scenarios (2 passed)
8 steps (8 passed)
0m1.24s (30.72Mb)