| 148 |
lars |
1 |
.. index::
|
|
|
2 |
single: Cookbook; Complex Argument Matching With Mockery::on
|
|
|
3 |
|
|
|
4 |
Complex Argument Matching With Mockery::on
|
|
|
5 |
==========================================
|
|
|
6 |
|
|
|
7 |
When we need to do a more complex argument matching for an expected method call,
|
|
|
8 |
the ``\Mockery::on()`` matcher comes in really handy. It accepts a closure as an
|
|
|
9 |
argument and that closure in turn receives the argument passed in to the method,
|
|
|
10 |
when called. If the closure returns ``true``, Mockery will consider that the
|
|
|
11 |
argument has passed the expectation. If the closure returns ``false``, or a
|
|
|
12 |
"falsey" value, the expectation will not pass.
|
|
|
13 |
|
|
|
14 |
The ``\Mockery::on()`` matcher can be used in various scenarios — validating
|
|
|
15 |
an array argument based on multiple keys and values, complex string matching...
|
|
|
16 |
|
|
|
17 |
Say, for example, we have the following code. It doesn't do much; publishes a
|
|
|
18 |
post by setting the ``published`` flag in the database to ``1`` and sets the
|
|
|
19 |
``published_at`` to the current date and time:
|
|
|
20 |
|
|
|
21 |
.. code-block:: php
|
|
|
22 |
|
|
|
23 |
<?php
|
|
|
24 |
namespace Service;
|
|
|
25 |
class Post
|
|
|
26 |
{
|
|
|
27 |
public function __construct($model)
|
|
|
28 |
{
|
|
|
29 |
$this->model = $model;
|
|
|
30 |
}
|
|
|
31 |
|
|
|
32 |
public function publishPost($id)
|
|
|
33 |
{
|
|
|
34 |
$saveData = [
|
|
|
35 |
'post_id' => $id,
|
|
|
36 |
'published' => 1,
|
|
|
37 |
'published_at' => gmdate('Y-m-d H:i:s'),
|
|
|
38 |
];
|
|
|
39 |
$this->model->save($saveData);
|
|
|
40 |
}
|
|
|
41 |
}
|
|
|
42 |
|
|
|
43 |
In a test we would mock the model and set some expectations on the call of the
|
|
|
44 |
``save()`` method:
|
|
|
45 |
|
|
|
46 |
.. code-block:: php
|
|
|
47 |
|
|
|
48 |
<?php
|
|
|
49 |
$postId = 42;
|
|
|
50 |
|
|
|
51 |
$modelMock = \Mockery::mock('Model');
|
|
|
52 |
$modelMock->shouldReceive('save')
|
|
|
53 |
->once()
|
|
|
54 |
->with(\Mockery::on(function ($argument) use ($postId) {
|
|
|
55 |
$postIdIsSet = isset($argument['post_id']) && $argument['post_id'] === $postId;
|
|
|
56 |
$publishedFlagIsSet = isset($argument['published']) && $argument['published'] === 1;
|
|
|
57 |
$publishedAtIsSet = isset($argument['published_at']);
|
|
|
58 |
|
|
|
59 |
return $postIdIsSet && $publishedFlagIsSet && $publishedAtIsSet;
|
|
|
60 |
}));
|
|
|
61 |
|
|
|
62 |
$service = new \Service\Post($modelMock);
|
|
|
63 |
$service->publishPost($postId);
|
|
|
64 |
|
|
|
65 |
\Mockery::close();
|
|
|
66 |
|
|
|
67 |
The important part of the example is inside the closure we pass to the
|
|
|
68 |
``\Mockery::on()`` matcher. The ``$argument`` is actually the ``$saveData`` argument
|
|
|
69 |
the ``save()`` method gets when it is called. We check for a couple of things in
|
|
|
70 |
this argument:
|
|
|
71 |
|
|
|
72 |
* the post ID is set, and is same as the post ID we passed in to the
|
|
|
73 |
``publishPost()`` method,
|
|
|
74 |
* the ``published`` flag is set, and is ``1``, and
|
|
|
75 |
* the ``published_at`` key is present.
|
|
|
76 |
|
|
|
77 |
If any of these requirements is not satisfied, the closure will return ``false``,
|
|
|
78 |
the method call expectation will not be met, and Mockery will throw a
|
|
|
79 |
``NoMatchingExpectationException``.
|
|
|
80 |
|
|
|
81 |
.. note::
|
|
|
82 |
|
|
|
83 |
This cookbook entry is an adaption of the blog post titled
|
|
|
84 |
`"Complex argument matching in Mockery" <https://robertbasic.com/blog/complex-argument-matching-in-mockery/>`_,
|
|
|
85 |
published by Robert Basic on his blog.
|