Loïc Faugeron Technical Blog

SpecGen v0.3 28/05/2015

TL;DR: SpecGen v0.3 inserts a property for each constructor argument.

SpecGen is a phpspec extension which enhance its code generator. With the latest release, v0.3, we get the following features:

Here's a simple example to demonstrate how helpful it can be.

Example

First of all, we need to set up a project with Composer. Let's write the following composer.json:

{
    "name": "vendor/project",
    "autoload": {
        "psr-4": {
            "Vendor\\Project\\": "src/Vendor/Project"
        }
    },
    "require": {},
    "require-dev": {}
}

Then we can install phpspec with SpecGen by running those commands:

composer require --dev phpspec/phpspec:~2.2
composer require --dev memio/spec-gen:~0.3
echo 'extensions:' > phpspec.yml
echo '  - Memio\SpecGen\MemioSpecGenExtension' >> phpspec.yml

In our example, we'll specify a TextEditor service, it should be able to create new files by relying on Filesystem, another service.

This can be done as follow:

phpspec describe 'Vendor\Project\TextEditor'
````

> **Tip**: make your vendor's binaries available by adding `vendor/bin` to your `$PATH`.
> `export PATH="vendor/bin:$PATH"`.

This should generate a `spec\Vendor\Project\TextEditorSpec.php` file:

```php
<?php

namespace spec\Vendor\Project;

use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

class TextEditorSpec extends ObjectBehavior
{
    function it_is_initializable()
    {
        $this->shouldHaveType('Vendor\Project\TextEditor');
    }
}

It needs to be edited to fit our needs:

<?php

namespace spec\Vendor\Project;

use Vendor\Project\Service\Filesystem;
use Vendor\Project\File;
use PhpSpec\ObjectBehavior;

class TextEditorSpec extends ObjectBehavior
{
    const FILENAME = '/tmp/file.txt';
    const FORCE_FILE_CREATION = true;

    function let(Filesystem $filesystem)
    {
        $this->beConstructedWith($filesystem);
    }

    function it_creates_new_files(File $file, Filesystem $filesystem)
    {
        $filesystem->exists(self::FILENAME)->willReturn(false);
        $filesystem->create(self::FILENAME)->willReturn($file);

        $this->open(self::FILENAME, self::FORCE_FILE_CREATION)->shouldBe($file);
    }
}

The Test Driven Development cycle advises us to run the test suite now:

phpspec run

This will bootstrap the following code:

<?php

namespace Vendor\Project;

use Vendor\Project\Service\Filesystem;

class TextEditor
{
    private $filesystem;

    public function __construct(Filesystem $filesystem)
    {
        $this->filesystem = $filesystem;
    }

    public function open($argument1, $argument2)
    {
    }
}

It created a filesystem property to mirror the constructor arguments. Neat!

What's next?

In our example phpspec also generated the collaborators (File and Filesystem). These don't beneficiate from SpecGen help yet, so the next release (v0.4) will probably be about using it for collaborators.

Other features that could be implemented would be PHPdoc generation, or avoiding the Interface / Abstract suffix/prefix in interface and abstract object argument names.

Reference: see the phpspec reference article