Kevin Nagurski
Kevin Nagurski

Reputation: 1889

How can I create an array of mocks in PHPSpec?

I've just started using PHPSpec and I'm really enjoying it over PHPUnit, especially the no-effort mocks and stubs. Anyway, the method I'm trying to test expects an array of Cell objects. How can I tell PHPSpec to give me an array of mocks?

Simplified version of my class

<?php
namespace Mything;

class Row
{
    /** @var Cell[] */
    protected $cells;


    /**
     * @param Cell[] $cells
     */
    public function __construct(array $cells)
    {
        $this->setCells($cells);
    }

    /**
     * @param Cell[] $cells
     * @return Row
     */
    public function setCells(array $cells)
    {
        // validate that $cells only contains instances of Cell

        $this->cells = $cells;

        return $this;
    }
}

Simplified version of my test

<?php
namespace spec\MyThing\Row;

use MyThing\Cell;
use PhpSpec\ObjectBehavior;

class RowSpec extends ObjectBehavior
{
    function let()
    {
        // need to get an array of Cell objects
        $this->beConstructedWith($cells);
    }

    function it_is_initializable()
    {
        $this->shouldHaveType('MyThing\Row');
    }

    // ...
}

I had hoped I could do the following, but it then complains that it can't find Cell[]. Using the FQN it complains about not being able to find \MyThing\Cell[].

/**
 * @param Cell[] $cells
 */
function let($cells)
{
    // need to get an array of Cell objects
    $this->beConstructedWith($cells);
}

The only options I can work out is to pass multiple type-hinted Cell arguments and manually combine them into an array. Am I missing something simple?

Edit: I'm using PHPSpec 2.5.3 as, unfortunately the server is currently stuck at PHP 5.3 :-(

Upvotes: 2

Views: 725

Answers (1)

DonCallisto
DonCallisto

Reputation: 29932

Why don't you do something like

use Prophecy\Prophet;
use Cell; // adapt it with PSR-4 and make it use correct class

class RowSpec extends ObjectBehavior
{
    private $prophet;
    private $cells = [];

    function let()
    {
        $this->prophet = new Prophet();

        for ($i = 0; $i < 10; $i++) {
            $this->cells[] = $this->prophet->prophesize(Cell::class);
        }
        $this->beConstructedWith($cells);
    }
    // ....

    function letGo()
    {
        $this->prophet->checkPredictions();
    }

    public function it_is_a_dummy_spec_method()
    {
         // use here your cells mocks with $this->cells
         // and make predictions on them
    }
}

Explanation

In let function you instantiate a Prophet object that is, basically a mocking library/framework that is used in tandem with PHPSpec (that itself use Prophecy).
I suggest to keep the instance ($this->prophet) as will be useful for next steps.

Now, you have to create your mocks, and you can do with prophet and prophesize.
Even for the mocks, I suggest to keep them into a private variable that you probably use for predictions in your methods.

letGo function is here to check explicitly the expectations you have made on cells: without, cells are only stubs or dummies.

Of course it's handy to pass through method signature a mock and to skip checkPredictions explicitly but, as soon as you need an array of mocks, I suppose that this is the only way to reach your goal.

Upvotes: 1

Related Questions