Behat and Guzzle
Behat is a behaviour driven development framework for the PHP application. Behat can be used for acceptance testing and api testing.
Guzzle is PHP HTTP client to work with HTTP and web services. You can read more about Guzzle on the official website . We can use combination of the Behat and Guzzle for the testing of the REST API. In this post, we will see how to use Guzzle http for testing GitHub web services.
Behat in Action
Let’s do some action now. We will install behat, create feature simple file and implement step definitions.
Installation & Config
Let’s create our composer.json to install all the dependencies with composer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ mkdir RESTful-Behat $ cd RESTful-Behat $ vim composer.json { "require": { "behat/behat": "2.4.0", "guzzle/guzzle": "2.4.*", "guzzlehttp/guzzle": "4.*" }, "config": { "bin-dir": "bin/" } } |
Now, we need to download composer and install all these dependencies
1 2 |
$curl http://getcomposer.org/installer | php $php composer.phar install |
This will install all the dependencies in the ‘vendor’ directory. Now we will create config file for behat.
1 2 3 4 5 |
# behat.yml default: context: parameters: base_url: https://api.github.com |
Note, we have created basic config for the behat. Now initialise Behat so that, Behat will create ‘bootstrap’ directory and ‘FeatureContext.php’ file.
1 |
$ ./bin/behat --init |
Create Feature file
In order to test the GitHub’s REST API with Behat, we need to create a feature file in the plain english. Our feature file should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ vim github_rest_api.feature Feature: GitHub RestFul Api Testing with Behat As a behat user I want to test restful api of the GitHub So that it will bring smile for behat community Scenario: GitHub behat Demo Api Given I request "/repos/Shashikant86/BehatDemo" Then the response should be JSON And the response status code should be 200 And the response has a "name" property And the "name" property equals "BehatDemo" |
As we read the feature file, we can understand that we are checking response format, response code and properties of the response a.k.a response body. At this point, we need to run ‘behat’ to get undefined steps. We need to implement these steps in the ‘FeatureContext.php’ file.
Step Definitions
Now, it’s time to implement step definitions using all the methods of the Guzzle Http library.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
$ vim features/bootstrap/FeatureContext.php <?php use Behat\Behat\Context\ClosuredContextInterface, Behat\Behat\Context\TranslatedContextInterface, Behat\Behat\Context\BehatContext, Behat\Behat\Exception\PendingException; use Behat\Gherkin\Node\PyStringNode, Behat\Gherkin\Node\TableNode; use GuzzleHttp\Client; class FeatureContext extends BehatContext { public $_response; public $_client; private $_parameters = array(); /** * Initializes context. * Every scenario gets it's own context object. * * @param array $parameters context parameters (set them up through behat.yml) */ public function __construct(array $parameters) { $this->_parameters = $parameters; $baseUrl = $this->getParameter('base_url'); $client = new Client(['base_url' => $baseUrl]); $this->_client = $client; } public function getParameter($name) { if (count($this->_parameters) === 0) { throw new \Exception('Parameters not loaded!'); } else { $parameters = $this->_parameters; return (isset($parameters[$name])) ? $parameters[$name] : null; } } /** * @When /^I request "([^"]*)"$/ */ public function iRequest($uri) { $request = $this->_client->get($uri); $this->_response = $request; } /** * @Then /^the response should be JSON$/ */ public function theResponseShouldBeJson() { $data = json_decode($this->_response->getBody(true)); if (empty($data)) { throw new Exception("Response was not JSON\n" . $this->_response); } } /** * @Then /^the response status code should be (\d+)$/ */ public function theResponseStatusCodeShouldBe($httpStatus) { if ((string)$this->_response->getStatusCode() !== $httpStatus) { throw new \Exception('HTTP code does not match '.$httpStatus. ' (actual: '.$this->_response->getStatusCode().')'); } } /** * @Given /^the response has a "([^"]*)" property$/ */ public function theResponseHasAProperty($propertyName) { $data = json_decode($this->_response->getBody(true)); if (!empty($data)) { if (!isset($data->$propertyName)) { throw new Exception("Property '".$propertyName."' is not set!\n"); } } else { throw new Exception("Response was not JSON\n" . $this->_response->getBody(true)); } } /** * @Then /^the "([^"]*)" property equals "([^"]*)"$/ */ public function thePropertyEquals($propertyName, $propertyValue) { $data = json_decode($this->_response->getBody(true)); if (!empty($data)) { if (!isset($data->$propertyName)) { throw new Exception("Property '".$propertyName."' is not set!\n"); } if ($data->$propertyName !== $propertyValue) { throw new \Exception('Property value mismatch! (given: '.$propertyValue.', match: '.$data->$propertyName.')'); } } else { throw new Exception("Response was not JSON\n" . $this->_response->getBody(true)); } } } |
We have implemented all the steps to test GitHub REST API. At this point, we will see all the steps has been passing
GitHub-Code
The source code for this demo is available on the GitHub at ‘RESTful-Behat‘ repo. You can try this by yourself
https://github.com/Shashikant86/RESTful-Behat
1 2 3 4 5 |
$ git clone git@github.com:Shashikant86/RESTful-Behat.git $ cd RESTful-Behat $curl http://getcomposer.org/installer | php $php composer.phar install $./bin/behat |
Video-Demo
Watch video demo of this demo on youtube
HAPPY API TESTING !!