PSSMockeryBundle + PHPSpec: The Automation Of Mocking Services Begins!

Let’s say we want to spec a service we are trying to design and we want to use PHPSpec in order to do that.
Our system runs supported by the Symfony2 Components/Framework and according to the rules of the Dependency Injection game we have a client running the application from where we can get all the services of the project the container holds.
Since our service is meant to live within this “Sitz im Leben” or context and would need some interaction with other services we would like to develop the service classes right without leaving at any time this environment.

Welcome to PSSMockeryBundle world. Thanks to Jakub Zalas creator of PSSMockeryBundle, we have something that was meant to solve the problem indicated above by setting up a base class for the container in which we can easily mock any service on the container. Tie this with PHPSpec and you are about to discover a framework setup in which anyone can easily start creating, stubbing, mocking and perfecting their service design for their bundles and craft carefully their dependencies on other services.

<?php
namespace Acme\DemoBundle\Spec\Model;
 
use Symfony\Bundle\FrameworkBundle\Spec\WebSpec;
use Acme\DemoBundle\Model\MyService;
use Twig_Environment;
 
class DescribeMyService extends WebSpec
{
    protected $container;
    protected $client;
    protected $serviceUnderSpec;
 
    public function before()
    {
        $this->client = self::createClient();
        $this->container = $this->client->getContainer();
        $this->serviceUnderSpec = $this->spec(new MyService($this->container));
    }
 
    /**
     * Specking MyService class mocking another service directly related
     */
    public function itShouldGetCreateDirectoryUsingFileSystemServiceFromContainer()
    {
        $filesystemMock = $this->container->mock('filesystem', 'Symfony\Component\Filesystem\Filesystem');
        $filesystemMock->shouldReceive('mkdir')->once()->andReturn(true);
 
        $this->serviceUnderSpec->methodUsingFileSystem()->should->beTrue();
    }
 
    /**
     * Specking MyService method that uses the router service
     * we do not mock the routing but we do mock the Twig_Environment service
     * used by the router
     */
    public function itShouldIndirectlyMockServiceTheRouterDependsOn()
    {
        $twigEnvironmentMock = $this->container->mock('twig','\Twig_Environment');
        $this->serviceUnderSpec->methodUsingRouter()->should->be('/');
    }
}

We first have created a Spec class to speck our new service `MyService` non-existent at this time. The idea is to write one example method at a time. Here we have just gone ahead and written the two we are interested in demoing. Then we proceed to run:

~ phpspec src/Acme/DemoBundle/Spec/

Then we get an error telling us to create the methods on our empty class:

~ phpspec src/Acme/DemoBundle/Spec/
EE
 
Exceptions:
 
  1) Acme\DemoBundle\Spec\Model\MyService should get create directory using file system service from container
     Failure\Exception: $this->runExamples($exampleGroup, $reporter);
     ErrorException: Warning: call_user_func_array() expects parameter 1 to be a valid callback, class 'Acme\DemoBundle\Model\MyService' does not have a method 'methodUsingFileSystem' in /home/cordoval/sites-2/spec-symfony/vendor/phpspec/src/PHPSpec/Specification/Interceptor/Object.php line 66
 
  2) Acme\DemoBundle\Spec\Model\MyService should run command on client
     Failure\Exception: $this->runExamples($exampleGroup, $reporter);
     ErrorException: Warning: call_user_func_array() expects parameter 1 to be a valid callback, class 'Acme\DemoBundle\Model\MyService' does not have a method 'methodUsingRouter' in /home/cordoval/sites-2/spec-symfony/vendor/phpspec/src/PHPSpec/Specification/Interceptor/Object.php line 66
 
Finished in 0.052649 seconds
2 examples, 2 exceptions

Next is writing just about enough code on our Service class to make the examples pass. For that we take a look at our `MyService` class:

<?php
namespace Acme\DemoBundle\Model;
 
class MyService
{
    protected $container;
 
    public function __construct($container)
    {
        $this->container = $container;
    }
 
    public function methodUsingFileSystem()
    {
        $filesystem = $this->container->get('filesystem');
        return $filesystem->mkdir('folder1');
    }
 
    public function methodUsingRouter()
    {
        $router = $this->container->get('router');
        return $router->generate('_welcome');
    }
 
    public function checkInternalResponse()
    {
        return true;
    }
}

If you fail to meet the requirements with the writing of your methods, don’t worry PHPSpec is here to guide you make that example green:

~ phpspec src/Acme/DemoBundle/Spec/
.F
 
Failures:
 
  1) Acme\DemoBundle\Spec\Model\MyService should run command on client
     Failure\Error: $this->serviceUnderSpec->methodUsingRouter()->should->be('/somepath');
     expected '/somepath', got '/' (using be())
     # ./src/Acme/DemoBundle/Spec/Model/MyServiceSpec.php:39

Finished in 0.060213 seconds
2 examples, 1 failure

If we get everything right after all we should get:

~ phpspec src/Acme/DemoBundle/Spec/ -fd -c -b
Acme\DemoBundle\Spec\Model\MyService
  should get create directory using file system service from container
  should run command on client
 
Finished in 0.074234 seconds
2 examples

Notice that the examples are simple and are meant for you to see how easy is to use PHPSpec with PSSMockeryBundle within Symfony. We are using the spec-symfony sandbox available in our PHPSpec repos. A lot of effort is being put these days in bringing powerful tools for BDD Spec type of BDD methodology into Symfony2. PHPSpecBundle is the leading bundle along these lines that will have commands to generate the skeletons required to practice good BDD Spec type on Symfony2. BDD Spec and BDD Scenario complement each other so that is why it is important to keep the and use them together because they are more powerful together than separate.

I thank the Lord Jesus Christ for all the help in completing this effort through good friends and very good willing people like Jakub who is an expert in symfony2. We brainstormed once and next day he had the bundle ready. This is a very interesting community accomplishment! bravo!

One thought on “PSSMockeryBundle + PHPSpec: The Automation Of Mocking Services Begins!

  1. Pingback: Mocking Symfony Container services in Behat scenarios with Mockery

Leave a Reply

Your email address will not be published. Required fields are marked *