Last active
December 11, 2015 01:38
-
-
Save sveneisenschmidt/4524570 to your computer and use it in GitHub Desktop.
Test API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Wildly\Bundle\ApiBundle\Features\Context; | |
use Symfony\Component\HttpKernel\KernelInterface; | |
use Symfony\Component\HttpFoundation\ParameterBag; | |
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeExtensionGuesser; | |
use Symfony\Component\Process\Process; | |
use Behat\Symfony2Extension\Context\KernelAwareInterface; | |
use Behat\MinkExtension\Context\MinkContext; | |
use Behat\Behat\Context\BehatContext, | |
Behat\Behat\Event\SuiteEvent, | |
Behat\Behat\Event\ScenarioEvent, | |
Behat\Behat\Exception\PendingException; | |
use Behat\Gherkin\Node\PyStringNode, | |
Behat\Gherkin\Node\TableNode; | |
/** | |
* Feature context. | |
*/ | |
class FeatureContext extends BehatContext | |
{ | |
/** | |
* @BeforeSuite | |
*/ | |
public static function prepareDatabase(SuiteEvent $event) | |
{ | |
$drop = self::spawn('app/console doctrine:schema:drop --force --env=test'); | |
$drop->run(); | |
if (!$drop->isSuccessful()) { | |
throw new \RuntimeException($process->getErrorOutput()); | |
} | |
$create = self::spawn('app/console doctrine:schema:update --force --env=test'); | |
$create->run(); | |
if (!$create->isSuccessful()) { | |
throw new \RuntimeException($process->getErrorOutput()); | |
} | |
$load = self::spawn('app/console doctrine:fixtures:load --env=test'); | |
$load->run(); | |
if (!$load->isSuccessful()) { | |
throw new \RuntimeException($process->getErrorOutput()); | |
} | |
} | |
/** | |
* @BeforeSuite | |
*/ | |
public static function spawn($command, $timout = 3600) | |
{ | |
$process = new Process($command); | |
$process->setTimeout(3600); | |
return $process; | |
} | |
/** | |
* | |
* @var Guzzle\Service\Client | |
*/ | |
protected $client; | |
/** | |
* | |
* @var array | |
*/ | |
protected $parameters = []; | |
/** | |
* | |
* @var array | |
*/ | |
protected $query = []; | |
/** | |
* | |
* @var array | |
*/ | |
protected $data = []; | |
/** | |
* | |
* @param array $parameters | |
*/ | |
public function __construct(array $parameters = []) | |
{ | |
$this->parameters = new ParameterBag($parameters); | |
$this->mimetypes = new MimeTypeExtensionGuesser(); | |
} | |
/** | |
* @BeforeScenario | |
*/ | |
public function setup() | |
{ | |
$this->client = new \Goutte\Client; | |
$this->query = new ParameterBag(); | |
$this->data = new ParameterBag(); | |
} | |
/** | |
* @Given /^that I want to "([^"]*)" a resource$/ | |
*/ | |
public function thatIWantToAResource($method) | |
{ | |
if(!in_array($method, ['GET', 'POST', 'PUT','PATCH', 'DELETE', 'HEAD'])) { | |
throw new \Exception(sprintf('Unknown method %s', $method)); | |
} | |
$this->method = strtoupper($method); | |
} | |
/** | |
* @Given /^that its query "([^"]*)" is "([^"]*)"$/ | |
*/ | |
public function thatItsQueryIs($key, $value) | |
{ | |
$this->query->set($key, $value); | |
} | |
/** | |
* @Given /^that its data "([^"]*)" is "([^"]*)"$/ | |
*/ | |
public function thatItsDataIs($key, $value) | |
{ | |
$this->data->set($key, $value); | |
} | |
/** | |
* @When /^I request "([^"]*)"$/ | |
*/ | |
public function iRequest($path) | |
{ | |
if(false === $this->parameters->has('base_url')) { | |
throw new \Exception(sprintf('Missing parameter %s', 'base_url')); | |
} | |
$base = $this->parameters->get('base_url'); | |
$data = $this->data->all(); | |
$query = http_build_query($this->query->all()); | |
$url = sprintf('%s/%s%s%s', | |
rtrim($base, '/'), | |
ltrim($path, '/'), | |
(true === empty($query)) ? '' : | |
((false !== strpos($path, '?')) ? '&' : '?'), | |
$query | |
); | |
$this->client->request($this->method, $url, $data); | |
} | |
/** | |
* @Given /^the response has a "([^"]*)" property$/ | |
*/ | |
public function theResponseHasAProperty($key) | |
{ | |
$response = $this->client->getResponse(); | |
$content = $response->getContent(); | |
$headers = $response->getHeaders(); | |
if(true === empty($headers['Content-Type'])) { | |
throw new \Exception('Header [Content-Type] not returned'); | |
} | |
$mimetype = $headers['Content-Type'][0]; | |
$data = $this->decode($mimetype, $content); | |
$bag = new ParameterBag($data); | |
if(null === $bag->get($key, null, true)) { | |
throw new \Exception(sprintf('Unknown property %s', $key)); | |
} | |
} | |
/** | |
* @Given /^the response should have the properties$/ | |
*/ | |
public function theResponseShouldHaveTheProperties(PyStringNode $string) | |
{ | |
foreach($string->getLines() as $line) { | |
$this->theResponseHasAProperty($line); | |
} | |
} | |
/** | |
* @Given /^the response header "([^"]*)" is set$/ | |
*/ | |
public function theResponseHeaderIsSet($key) | |
{ | |
$response = $this->client->getResponse(); | |
$content = $response->getContent(); | |
$headers = $response->getHeaders(); | |
if(false === array_key_exists($key, $headers) || true === empty($headers[$key])) { | |
throw new \Exception(sprintf('Header [%s] does not exist or is empty', $key)); | |
} | |
} | |
// ATTENTION | |
/** | |
* @Then /^the response status code should be (\d+)$/ | |
*/ | |
public function theResponseStatusCodeShouldBe($code) | |
{ | |
$response = $this->client->getResponse(); | |
if((int)$code !== ($status = $response->getStatus())) { | |
throw new \Exception(sprintf('Wrong status code returned (%s)', $status)); | |
} | |
} | |
/** | |
* @Then /^the response format is "([^"]*)"$/ | |
*/ | |
public function theResponseFormatIs($format) | |
{ | |
$this->theResponseHeaderIsSet('Content-Type'); | |
$format = strtolower($format); | |
$response = $this->client->getResponse(); | |
$content = $response->getContent(); | |
$headers = $response->getHeaders(); | |
$mimetype = $headers['Content-Type'][0]; | |
if($format !== $mimetype && $format !== $this->mimetypes->guess($mimetype)) { | |
throw new \Exception(sprintf('Wrong Content-Type %s returned', $mimetype)); | |
} | |
try { | |
$this->decode($mimetype, $content); | |
} catch(Exception $e) { | |
throw new \Exception('Response is no valid JSON'); | |
} | |
} | |
/** | |
* @Given /^the type of the "([^"]*)" property is "([^"]*)"$/ | |
*/ | |
public function theTypeOfThePropertyIs($key, $type) | |
{ | |
$this->theResponseHeaderIsSet('Content-Type'); | |
$this->theResponseHasAProperty($key); | |
$response = $this->client->getResponse(); | |
$content = $response->getContent(); | |
$headers = $response->getHeaders(); | |
$mimetype = $headers['Content-Type'][0]; | |
$data = $this->decode($mimetype, $content); | |
$bag = new ParameterBag($data); | |
$value = $bag->get($key, null, true); | |
switch($type) { | |
case 'integer': | |
if(false === is_int($value)) { | |
throw new \Exception(sprintf('Property %s is not of type %s', $key, $type)); | |
} | |
break; | |
case 'numeric': | |
if(false === is_numeric($value)) { | |
throw new \Exception(sprintf('Property %s is not of type %s', $key, $type)); | |
} | |
break; | |
case 'string': | |
if(false === is_string($value)) { | |
throw new \Exception(sprintf('Property %s is not of type %s', $key, $type)); | |
} | |
break; | |
default: | |
throw new \Exception(sprintf('Unsupported type %s', $type)); | |
} | |
} | |
/** | |
* @Given /^the value of the "([^"]*)" property is (\d+)$/ | |
*/ | |
public function theValueOfThePropertyIs($key, $value) | |
{ | |
$this->theResponseHeaderIsSet('Content-Type'); | |
$this->theResponseHasAProperty($key); | |
$response = $this->client->getResponse(); | |
$content = $response->getContent(); | |
$headers = $response->getHeaders(); | |
$mimetype = $headers['Content-Type'][0]; | |
$data = $this->decode($mimetype, $content); | |
$bag = new ParameterBag($data); | |
if($value != ($actual = $bag->get($key, null, true))) { | |
throw new \Exception(sprintf('Property %s has value %s not %s', $key, $value, $actual)); | |
} | |
} | |
/** | |
* @Given /^the value of the "([^"]*)" property is "([^"]*)"$/ | |
*/ | |
public function theValueOfThePropertyIs2($key, $value) | |
{ | |
$this->theValueOfThePropertyIs($key, $value); | |
} | |
/** | |
* Tries to code simple text based formats | |
* | |
* @param string $mimetype | |
* @param string $content | |
* @return array | |
*/ | |
protected function decode($mimetype, $content) | |
{ | |
switch($mimetype) { | |
case 'application/json': | |
if(null === ($data = json_decode($content, true))) { | |
throw new \Exception('Response is no valid JSON'); | |
} | |
break; | |
default: | |
throw new \Exception('Response body is in unknown format'); | |
} | |
return $data; | |
} | |
/** | |
* @Given /^the response should be empty$/ | |
*/ | |
public function theResponseShouldBeEmpty() | |
{ | |
$response = $this->client->getResponse(); | |
$content = $response->getContent(); | |
if(false === empty($content)) { | |
throw new \Exception('Response body is not empty'); | |
} | |
} | |
/** | |
* @Given /^the response header "([^"]*)" should be set$/ | |
*/ | |
public function theResponseHeaderShouldBeSet($key) | |
{ | |
$response = $this->client->getResponse(); | |
$content = $response->getContent(); | |
$headers = $response->getHeaders(); | |
if(false === array_key_exists($key, $headers) || true === empty($headers[$key])) { | |
throw new \Exception(sprintf('Header [%s] does not exist or is empty', $key)); | |
} | |
} | |
/** | |
* @Given /^debug response$/ | |
*/ | |
public function debugResponse() | |
{ | |
print PHP_EOL; | |
print_r($this->client->getResponse()); | |
print PHP_EOL; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# features/pet.feature | |
Feature: Testing the Pet API | |
# AUTH | |
Scenario: Authetication fails: Missing token | |
Given that I want to "GET" a resource | |
When I request "/pets/1" | |
And the response status code should be 400 | |
And the value of the "status" property is "error" | |
And the value of the "status_text" property is "Bad Request" | |
And the value of the "message" property is "Missing authentication token." | |
Scenario: Authetication fails: Wrong token | |
Given that I want to "GET" a resource | |
And that its query "_token" is "WRONG_TOKEN" | |
When I request "/pets/1" | |
And the response status code should be 400 | |
And the value of the "status" property is "error" | |
And the value of the "status_text" property is "Bad Request" | |
And the value of the "message" property is "Invalid authentication token." | |
# GET | |
Scenario: Pet exists | |
Given that I want to "GET" a resource | |
And that its query "_token" is "TEST_TOKEN" | |
When I request "/pets/1" | |
Then the response format is "JSON" | |
And the response status code should be 200 | |
And the response header "Content-Type" is set | |
And the response should have the properties | |
""" | |
id | |
created_at | |
updated_at | |
creature[id] | |
title | |
owner | |
""" | |
And the type of the "id" property is "integer" | |
And the value of the "id" property is 1 | |
Scenario: Pet does not exist | |
Given that I want to "GET" a resource | |
And that its query "_token" is "TEST_TOKEN" | |
When I request "/pets/999999999" | |
Then the response format is "JSON" | |
And the response status code should be 404 | |
And the value of the "status" property is "error" | |
And the value of the "status_text" property is "Not Found" | |
# PATCH | |
Scenario: Partially updates Pet | |
Given that I want to "POST" a resource | |
And that its query "_token" is "TEST_TOKEN" | |
And that its query "_method" is "PATCH" | |
And that its data "title" is "TEST Scenario #PATCH" | |
When I request "/pets/1" | |
And the response status code should be 204 | |
And the response should be empty | |
Scenario: Load updated Pet | |
Given that I want to "GET" a resource | |
And that its query "_token" is "TEST_TOKEN" | |
When I request "/pets/1" | |
And the response status code should be 200 | |
And the value of the "title" property is "TEST Scenario #PATCH" | |
# POST | |
Scenario: Fully update Pet with new data | |
Given that I want to "POST" a resource | |
And that its query "_token" is "TEST_TOKEN" | |
And that its data "title" is "TEST Scenario #POST" | |
And that its data "description" is "TEST Scenario #POST" | |
When I request "/pets/1" | |
And the response status code should be 204 | |
And the response should be empty | |
Scenario: Load updated Pet | |
Given that I want to "GET" a resource | |
And that its query "_token" is "TEST_TOKEN" | |
When I request "/pets/1" | |
And the response status code should be 200 | |
And the value of the "title" property is "TEST Scenario #POST" | |
And the value of the "description" property is "TEST Scenario #POST" | |
Scenario: Fully update Pet with insufficient data | |
Given that I want to "POST" a resource | |
And that its query "_token" is "TEST_TOKEN" | |
And that its data "title" is "TEST Scenario" | |
When I request "/pets/1" | |
And the response status code should be 400 | |
And the value of the "status" property is "error" | |
And the value of the "status_text" property is "Bad Request" | |
And the value of the "message" property is "Validation failed" | |
# PUT | |
Scenario: Create new Pet | |
Given that I want to "POST" a resource | |
And that its query "_method" is "PUT" | |
And that its query "_token" is "TEST_TOKEN" | |
And that its data "title" is "TEST Scenario #PUT1" | |
And that its data "description" is "TEST Scenario #PUT1" | |
And that its data "owner" is "1" | |
And that its data "creature" is "1" | |
When I request "/pets" | |
And the response status code should be 200 | |
And the value of the "id" property is 11 | |
And the value of the "title" property is "TEST Scenario #PUT1" | |
And the value of the "description" property is "TEST Scenario #PUT1" | |
And the value of the "creature[id]" property is 1 | |
And the value of the "owner[id]" property is 1 | |
Scenario: Create new Pet without redirect | |
Given that I want to "POST" a resource | |
And that its query "_method" is "PUT" | |
And that its query "_token" is "TEST_TOKEN" | |
And that its data "title" is "TEST Scenario #PUT2" | |
And that its data "description" is "TEST Scenario #PUT2" | |
And that its data "owner" is "1" | |
And that its data "creature" is "1" | |
And do not follow redirects | |
When I request "/pets" | |
And the response status code should be 201 | |
And the response should be empty | |
Scenario: Load creatd Pet manually | |
Given that I want to "GET" a resource | |
And that its query "_token" is "TEST_TOKEN" | |
When I request "/pets/12" | |
And the response status code should be 200 | |
And the value of the "id" property is 12 | |
And the value of the "title" property is "TEST Scenario #PUT2" | |
And the value of the "description" property is "TEST Scenario #PUT2" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment