If you know PHPSpec a bit, you certainly are aware of let
function.
1 2 3 4 |
function let(EntityManager $em) { $this->beConstructedWith($em); } |
that helps you to define “automagic” mocks handled directly by PHPSpec and that you can pass to your example
1 2 3 4 5 |
public function it_use_entity_manager(EntityManager $em) { // ... $em->persist(Argument::any())->shouldBeCalled(); } |
If type and name of your mock is the same of let
function, then the mock is the same! And this is very helpful when you want to make predictions and when you want to check them as PHPSpec will take care of it for you!
BUT …
What about an array of mocks passed into constructor of the class you are spec-ing?
Let’s take a look to the following example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Class Foo { public function __construct(array $bars) { // bars is an array of Bar object that will be used // into Foo as collaborators // ... } } class Bar { // ... } |
As you can imagine, you cannot pass the “automagic” mock (mocks) in this situation. So the question is: “how to use the *same* mocks in let
function and in our examples?
Nothing easier!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
class FooSpec { private $prophet; private $bars = []; function let() { $this->prophet = new Prophet(); for ($i = 0; $i < 10; $i++) { $this->bars[] = $this->prophet->prophesize(Bar::class); } $this->beConstructedWith($this->bars); } function it_use_bars() { // use $this->bars as mocks to make some predictions } function letGo() { $this->prophet->checkPredictions(); } |
Explanation
In let
function you instantiate a Prophet
object that is, basically a mocking library/framework that is used in tandem with PHPSpec (which itself use Prophecy).
I suggest to keep the instance ($this->prophet
) as it will be useful for next steps (letGo
).
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 will be used for predictions in your examples (it_use_bars
)
letGo
function is here to check explicitly (no signature mocks, no magic!) the expectations you have made on bars
: without checkPredictions
, bars
are only stubs
or dummies.
Of course you can use prophet
and this approach not only for constructor but for any mock that you could not or you don’t want to pass as a parameter.
This tutorial is very tiny but, in my humble opinion, could be a time saver for many newbie users!
See you next time!
S.
HI Samuele,
thanks for the tip. I’ve just used to simulate a bunch of mocks to have them available across the examples, even using willReturn with another mocks as parameter. It’s really great to create some complex examples.
Hi Fran,
thank you for reading us and for this comment.
It’s always a pleasure when your blog posts are useful for others.
Please keep follow us for brand new contents.
Have a nice day!
S.
I am trying to pass an array of mocks into an object and am getting errors.
Don’t you have to invoke reveal() to get the actual mocks?
Yes, you need to invoke
reveal