mirror of
https://github.com/silverstripe/silverstripe-behat-extension
synced 2024-06-15 17:21:43 +02:00
UNFINISHED Webservice tutorial
This commit is contained in:
parent
4f8039d39f
commit
5be95105ff
|
@ -8,28 +8,24 @@ SOAP is a common web service layer to achieve this level of interaction.
|
||||||
|
|
||||||
Web services have a couple of disadvantages when it comes to testing though:
|
Web services have a couple of disadvantages when it comes to testing though:
|
||||||
|
|
||||||
- They're slow down our tests, responding in seconds rather than milliseconds
|
- They slow down our tests, responding in seconds rather than milliseconds
|
||||||
- Their data can change over time, making it hard to start with a clean slate
|
- Their data can change over time, making it hard to start with a clean slate
|
||||||
- They're not isolated, meaning multiple test runs accessing a webservice in parallel can cause side effects for each other
|
- They're not isolated, meaning multiple test runs accessing a webservice in parallel can cause side effects for each other
|
||||||
- Since their data isn't defined in our tests, its hard to understand the assumptions and requirements of a test.
|
- Since their data isn't defined in our tests, its hard to understand the assumptions and requirements of a test.
|
||||||
|
|
||||||
This is where mocks objects come in, which replace the "real"
|
This is where fake objects come in, which replace the "real" webservice with a fake data defined in our test framework.
|
||||||
webservice with a fake data defined in our test framework.
|
The challenge is to get these fakes defined in a way that allows sharing of state
|
||||||
The challenge is to get mocks defined as in-memory objects via PHP
|
between the Behat test executed on the commandline, and the various PHP processes
|
||||||
while executing Behat steps on the commandline, but applying those
|
launched in a browser based on this test.
|
||||||
same mocks in a different process when Behat/Mink/Selenium
|
|
||||||
perform a web request. That's solved by generated PHP code which is
|
|
||||||
included as part of the bootstrap process.
|
|
||||||
|
|
||||||
There's several parts to this:
|
There's several parts to this:
|
||||||
|
|
||||||
- [Behat](http://behat.org) parses features into executable steps
|
- [Behat](http://behat.org) parses features into executable steps
|
||||||
- [Mink](http://mink.behat.org) interacts with [Selenium](http://selenium.googlecode.com) to remote control a browser
|
- [Mink](http://mink.behat.org) interacts with [Selenium](http://selenium.googlecode.com) to remote control a browser
|
||||||
- PHP's built-in `SoapClient` is used for the "real" API connection
|
- PHP's built-in `SoapClient` is used for the "real" API connection
|
||||||
- A "gateway" class which encapsulates the SOAP interactions
|
- A "gateway" class which encapsulates the webservice interactions
|
||||||
- [Phockito](https://github.com/hafriedlander/phockito) as a mocking framework to "hardcode" method returns
|
- The [testsession module](https://github.com/silverstripe-labs/silverstripe-testsession) creates a "sandbox" environment with a fresh database, and allows sharing state between command line and web requests
|
||||||
- The `TestSessionStubCodeWriter` which writes PHP code to be included only in test runs.
|
- The [fakedatabase module](https://github.com/chillu/fakedatabase) persists arbitrary key/value pairs in a temporary JSON file
|
||||||
In our case it contains Phockito mock object definitions.
|
|
||||||
|
|
||||||
## Example: A Currency Conversion Rate Viewer
|
## Example: A Currency Conversion Rate Viewer
|
||||||
|
|
||||||
|
@ -52,10 +48,10 @@ Feature:
|
||||||
Then I should see "NZD -> EUR: 1.56"
|
Then I should see "NZD -> EUR: 1.56"
|
||||||
```
|
```
|
||||||
|
|
||||||
Follow the [Behat+SilverStripe installation instructions](https://github.com/silverstripe-labs/silverstripe-behat-extension), then install the Phockito mocking framework:
|
Follow the [Behat+SilverStripe installation instructions](https://github.com/silverstripe-labs/silverstripe-behat-extension), then install the [fakedatabase](https://github.com/chillu/fakedatabase) dependency:
|
||||||
|
|
||||||
```
|
```
|
||||||
composer require hafriedlander/phockito:*
|
composer require chillu/fakedatabase:*
|
||||||
```
|
```
|
||||||
|
|
||||||
First we'll create a `CurrencyGateway` class which encapsulates a `SoapClient`
|
First we'll create a `CurrencyGateway` class which encapsulates a `SoapClient`
|
||||||
|
@ -83,7 +79,7 @@ We'll stick to request parameters and plaintext responses just to keep the code
|
||||||
manageable, a more realistic controller would likely use a form and HTML formatted responses.
|
manageable, a more realistic controller would likely use a form and HTML formatted responses.
|
||||||
Its important that our `CurrencyGateway` is instanciated through the
|
Its important that our `CurrencyGateway` is instanciated through the
|
||||||
use of [dependency injection](http://doc.silverstripe.org/framework/en/trunk/reference/injector),
|
use of [dependency injection](http://doc.silverstripe.org/framework/en/trunk/reference/injector),
|
||||||
so we can replace its implementation with a mock object later.
|
so we can replace its implementation with a fake object later.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// mysite/code/MyController.php
|
// mysite/code/MyController.php
|
||||||
|
@ -116,47 +112,23 @@ Open the already generated `FeatureContext.php` file and add the following code.
|
||||||
// mysite/tests/behat/features/bootstrap/Context/FeatureContext.php
|
// mysite/tests/behat/features/bootstrap/Context/FeatureContext.php
|
||||||
class FeatureContext extends SilverStripeContext {
|
class FeatureContext extends SilverStripeContext {
|
||||||
|
|
||||||
protected $stubCodeWriter;
|
protected $manager;
|
||||||
|
|
||||||
public function __construct() {
|
|
||||||
// ...
|
|
||||||
|
|
||||||
$this->stubCodeWriter = Injector::inst()->get('TestSessionStubCodeWriter');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @BeforeScenario
|
* @BeforeScenario
|
||||||
*/
|
*/
|
||||||
public function initTestSessionStubCode() {
|
public function createManager() {
|
||||||
$php = <<<PHP
|
// ...
|
||||||
\$mock = Phockito::mock('CurrencyGateway');
|
$testState = Injector::inst()->get('TestSessionEnvironment')->getState();
|
||||||
Injector::inst()->registerService(\$mock, 'CurrencyGateway');
|
$db = new FakeDatabase($testState->fakeDatabasePath);
|
||||||
PHP;
|
$this->manager = Injector::inst()->get('FakeManager', false, array($db));
|
||||||
$this->stubCodeWriter->write($php);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @AfterScenario
|
|
||||||
*/
|
|
||||||
public function resetTestSessionStubCode() {
|
|
||||||
$this->stubCodeWriter->reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTestSessionState() {
|
|
||||||
return array_merge(
|
|
||||||
parent::getTestSessionState(),
|
|
||||||
array('stubfile' => $this->stubCodeWriter->getFilePath())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Given /^I have a currency rate from "([^"]*)" to "([^"]*)" of "([^"]*)"$/
|
* @Given /^I have a currency rate from "([^"]*)" to "([^"]*)" of "([^"]*)"$/
|
||||||
*/
|
*/
|
||||||
public function stepGivenACurrency($from, $to, $rate) {
|
public function stepGivenACurrency($from, $to, $rate) {
|
||||||
$php = <<<PHP
|
$this->manager->getDb()->set('Currency', "{$from}-{$to}", $rate);
|
||||||
Phockito::when(\$mock->convert('$from','$to'))->return($rate);
|
|
||||||
PHP;
|
|
||||||
$writer->write($php);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -176,6 +176,7 @@ class SilverStripeContext extends MinkContext implements SilverStripeAwareContex
|
||||||
}
|
}
|
||||||
|
|
||||||
$state = $this->getTestSessionState();
|
$state = $this->getTestSessionState();
|
||||||
|
var_dump($state);
|
||||||
$this->testSessionEnvironment->startTestSession($state);
|
$this->testSessionEnvironment->startTestSession($state);
|
||||||
|
|
||||||
// Optionally import database
|
// Optionally import database
|
||||||
|
|
Loading…
Reference in New Issue
Block a user