This post is inspired in the development here.
I received great help from jbohn.
So we are starting according to certain scenario.
Feature: Member rents video As a video-club member I want to rent a video So that I can take it away with me and watch it conveniently at home Feature: Members rents video As a video-club member I want to rent a video So that I can take it away with me and watch it conveniently at home Scenario: Renting single video from oldies section Given I am in the "review" page And the selected video is "Revolution OS" When I click on "Rent" Then "£2" is added to my total Scenario: Renting 3 videos from oldies promotion Given I am in the "review" page And "Revolution OS" is selected And "Blade Runner" is selected And "The Wall" is selected When I click on "Rent" Then "£5" is added to my total |
Then we run behat on the file and we are getting:

There is an error with the view already. The reason why we have passed the first step is only because there is already a router for the framework and debugging enabled. However the page that is gotten back by the step is not really a valid page. Once we are at this point we go deeper into the PHPSpec cycle now.
We run the following command because phpspec installed via pear is not the one we are using. Why? Because it does not have knowledge of our updates and also it does not have knowledge of our third party libraries, and also because we want to have full control on what gets loaded. I ran into a redefine issue with function any() conflict between phpunit and hamcrest library.
So here is the command I use:
~/sites-2/FormModelProjectBundle (phpspec) vendor/phpspec/scripts/phpspec.php vendor/bundles/Cordova/Bundle/FormModelBundle/ |
The `phpspec` script is smart enough to look for the right Spec folder under the bundle and runs the phpspec for IndexSpec.php which is made locatable because of its Spec.php ending.
The resulting output of the previous command is:
E Exceptions: 1) Cordova\Bundle\FormModelBundle\Specs\views\Index renders the selected video Failure\Exception: $this->runExamples($exampleGroup, $reporter); InvalidArgumentException: Unable to find template "CordovaFormModelBundle:index.html.twig". Finished in 0.134287 seconds 1 example, 1 exception |
Notice here that it tells us that we have the wrong path for our template. Which theoretically is unimplemented. The exact error means that we actually need to insert the logical controller name between the ::. This is familiar to sf2 developers. So we do the change and having a lame default controller we have now the following error:
F Failures: 1) Cordova\Bundle\FormModelBundle\Specs\views\Index renders the selected video Failure\Error: $output->should->contain('Revolution OS'); expected to contain 'Revolution OS', found no match (using contain()) # ./vendor/bundles/Cordova/Bundle/FormModelBundle/Specs/views/IndexSpec.php:16 Finished in 1.080713 seconds 1 example, 1 failure |
Notice: we could have used the generation of a bundle. However since controllers are mostly custom code then there is no point really in using generator unless it is a new action to be placed in a new bundle. So there is no need in sf2 to use a generation command here unless in the case where we are putting things into a new bundle. For all other cases we just copy/paste a controller common template.
Now we know where all our efforts must concentrate, namely here $output->should->contain('Revolution OS');. This means the template rendered has nowhere the label `Revolution OS`. The major problem here is that we need to work on the loading of matchers for Symfony2.
Once we worked on the matcher `Contain` we can run the phpspec command again and we get:
vendor/phpspec/scripts/phpspec.php vendor/bundles/Cordova/Bundle/FormModelBundle/Specs/views/IndexSpec.php . Finished in 1.029784 seconds 1 example |
Now we are ready to head onto developing the C standing for the controller layer. The controller basically is in charge of doing the dispatching of things. So we need to work again on the Symfony2 controller version of things.
<?php class DescribeIndex extends View { function itRendersTheSelectedVideo() { $video = \Mockery::mock( 'Application_Model_Video', array('getName' => 'Revolution OS')); $output = $this->render('MyBundle:Video:detail.html.twig', array( 'video' => $video, ); $output->should->contain('Revolution OS'); } } |
<?php use PHPSpec\Context; use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface; class View extends Context { private $engine; public function setTemplatingEngine(EngineInterface $engine) { $this->engine = $engine; } public function spec() { $interceptor = call_user_func_array( array( '\PHPSpec\Specification\Interceptor\InterceptorFactory', 'create'), func_get_args() ); $interceptor->addMatchers(array('contain', 'haveSelector')); return $interceptor; } public function render($template, array $templateContext = array()) { if (is_null($this->engine)) { throw new \LogicException('No templating engine set.'); } return $this->spec($this->engine->render($template, $templateContext)); } } |