Magento TDD with PHPSpec

Reading Time: 4 minutes

Today, we are implementing the MageTest/MageSpec Module based on PHPSpec toolset.

In this implementation, we have two different tests taken from the Magecasts tutorials. The first one is to understand how PHPSpec works.

First Test

"We will look at PHPspec and how we can use it to enhance our development workflow".

Prerequisites

PHP 5.3.x or greater
Install composer

Getting Started

Create composer.json file

On root project, create composer.json file with the data below:
[ecko_code_highlight language="javascript"] {
"require-dev": {
"phpspec/phpspec": "~2.1"
},
"config": {
"bin-dir": "bin"
},
"autoload": {
"psr-0": {
"Crowd\\Store": "src"
}
}
}
[/ecko_code_highlight]

Run composer install

$ composer install

You will get something like this:

Loading composer repositories with package information
Installing dependencies (including require-dev)
    - Installing doctrine/instantiator (1.0.5)
    Loading from cache

    - Installing symfony/yaml (v2.7.2)
    Loading from cache

    - Installing symfony/process (v2.7.2)
    Loading from cache

    - Installing symfony/finder (v2.7.2)
    Loading from cache

    - Installing symfony/event-dispatcher (v2.7.2)
    Loading from cache

    - Installing symfony/console (v2.7.2)
    Loading from cache

    - Installing sebastian/recursion-context (1.0.0)
    Loading from cache

    - Installing sebastian/exporter (1.2.0)
    Loading from cache

    - Installing phpspec/php-diff (v1.0.2)
    Loading from cache

    - Installing sebastian/diff (1.3.0)
    Loading from cache

    - Installing sebastian/comparator (1.1.1)
    Loading from cache

    - Installing phpdocumentor/reflection-docblock (2.0.4)
    Loading from cache

    - Installing phpspec/prophecy (v1.4.1)
    Loading from cache

    - Installing phpspec/phpspec (2.2.1)
    Loading from cache

    symfony/event-dispatcher suggests installing symfony/dependency-injection ()
    symfony/event-dispatcher suggests installing symfony/http-kernel ()
    symfony/console suggests installing psr/log (For using the console logger)
    phpdocumentor/reflection-docblock suggests installing dflydev/markdown (~1.0)
    phpdocumentor/reflection-docblock suggests installing erusev/parsedown (~1.0)
    phpspec/phpspec suggests installing phpspec/nyan-formatters (~1.0 – Adds Nyan formatters)

PHPSpec run command

Now that we have bin/ and vendor/ directory in our project, let's go with this:

$ bin/phpsepc run

And you will see:

0 specs
0 examples
0ms

Play with PHPSpec

$ bin/phpspec describe Crowd/Store/Product

Will return this message:

Specification for Crowd\Store\Product created in [rootproject]/spec/Crowd/Store/ProductSpec.php

In your folder project now you will see

spec folder

The content of the ProductSpec.php created file looks like this:

[ecko_code_highlight language="php"] <?php

namespace spec\Crowd\Store;

use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

class ProductSpec extends ObjectBehavior
{
function it_is_initializable()
{
$this->shouldHaveType('Crowd\Store\Product');
}
}
[/ecko_code_highlight] On terminal type

$ bin/phpspec run

And now you will see this:

class does not exists

Type YES and you will get the next message:

class was created

And the next file structure in your project

src file structure

Inside Product.php you will see
[ecko_code_highlight language="php"] <?php

namespace Crowd\Store;

class Product
{
}
[/ecko_code_highlight]

Now inside [rootproject]/spec/Crowd/Store/ProductSpec.php file, write the next functions
[ecko_code_highlight language="php"] function it_should_have_a_name()
{
$this->getName()->shouldReturn('Testing Spec');
}

function it_should_have_sku()
{
$this->getSku()->shouldReturn('12345');
}
[/ecko_code_highlight] The complete files looks like:
[ecko_code_highlight language="php"] <?php

namespace spec\Crowd\Store;

use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

class ProductSpec extends ObjectBehavior
{
function it_is_initializable()
{
$this->shouldHaveType('Crowd\Store\Product');
}

function it_should_have_a_name()
{
$this->getName()->shouldReturn('Testing Spec');
}

function it_should_have_sku()
{
$this->getSku()->shouldReturn('12345');
}
}
[/ecko_code_highlight] What are we doing here? Well, we are defining two more test functions. One to check if a function called getName() returns a string with value "Testing Spec" and the other to check if a function called getSku() returns a string with value "12345".

On terminal lets do:

$ bin/phpspec run

It will display:

getName() function does not exists

Press Y + return key:

getSku() function does not exists

Press Y + return key again:

functions exists but tests does not pass

What does this mean? First of all, PHPSpec checks if getName() and getSku() functions exists in the Product class. If it does not find them, it asks us if we want to create them. Once created, PHPSpec will try to run the tests, but they will not pass.

The Product.php file under [rootproject]/src/Crowd/Store/ changed its content and now looks like:
[ecko_code_highlight language="php"] <?php

namespace Crowd\Store;

class Product
{

public function getName()
{
// TODO: write logic here
}

public function getSku()
{
// TODO: write logic here
}
}
[/ecko_code_highlight] That's the reason our tests are not passing: the functions exist, but they do nothing. Lets work with them and type the following in Product.php
[ecko_code_highlight language="php"] <?php

namespace Crowd\Store;

class Product
{

protected $_name;
protected $_sku;

public function __construct($name = '', $sku = '')
{
$this->_name = $name;
$this->_sku = $sku;
}

public function getName()
{
return $this->_name;
}

public function getSku()
{
return $this->_sku;
}
}
[/ecko_code_highlight] Run the specs again:

$ bin/phpspec run

And... oh!, they don't pass again. Why?

test not pass again

This happened because phpspec is running without any init data. To do that, let's type the following inside ProductSpec class:
[ecko_code_highlight language="php"] function let()
{
$name = "Testing Spec";
$sku = "12345";
$this->beConstructedWith($name, $sku);
}
[/ecko_code_highlight] The let() method is used to pass data into the constructor each time the parser gets created using the beConstructedWith() method

Now on the console, type once again

$ bin/phpspec run

test pass

And we did it, friends!

0 Shares:
You May Also Like
Read More

Using Knockout in Magento 2

Reading Time: 2 minutes Many people who are new to Magento and have read about Knockout JS before will think this is…
Read More

3 ecommerce platforms for retailers

Reading Time: 2 minutes Non-store retailing continues strengthening worldwide, and according to Euromonitor analyst, Amanda Bourlier, in 2021 sales for more than…