| 148 |
lars |
1 |
Mockery
|
|
|
2 |
=======
|
|
|
3 |
|
|
|
4 |
[](https://github.com/mockery/mockery/actions)
|
|
|
5 |
[](https://packagist.org/packages/mockery/mockery)
|
|
|
6 |
[](https://packagist.org/packages/mockery/mockery)
|
|
|
7 |
|
|
|
8 |
Mockery is a simple yet flexible PHP mock object framework for use in unit testing
|
|
|
9 |
with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a
|
|
|
10 |
test double framework with a succinct API capable of clearly defining all possible
|
|
|
11 |
object operations and interactions using a human readable Domain Specific Language
|
|
|
12 |
(DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library,
|
|
|
13 |
Mockery is easy to integrate with PHPUnit and can operate alongside
|
|
|
14 |
phpunit-mock-objects without the World ending.
|
|
|
15 |
|
|
|
16 |
Mockery is released under a New BSD License.
|
|
|
17 |
|
|
|
18 |
## Installation
|
|
|
19 |
|
|
|
20 |
To install Mockery, run the command below and you will get the latest
|
|
|
21 |
version
|
|
|
22 |
|
|
|
23 |
```sh
|
|
|
24 |
composer require --dev mockery/mockery
|
|
|
25 |
```
|
|
|
26 |
|
|
|
27 |
## Documentation
|
|
|
28 |
|
|
|
29 |
In older versions, this README file was the documentation for Mockery. Over time
|
|
|
30 |
we have improved this, and have created an extensive documentation for you. Please
|
|
|
31 |
use this README file as a starting point for Mockery, but do read the documentation
|
|
|
32 |
to learn how to use Mockery.
|
|
|
33 |
|
|
|
34 |
The current version can be seen at [docs.mockery.io](http://docs.mockery.io).
|
|
|
35 |
|
|
|
36 |
## PHPUnit Integration
|
|
|
37 |
|
|
|
38 |
Mockery ships with some helpers if you are using PHPUnit. You can extend the
|
|
|
39 |
[`Mockery\Adapter\Phpunit\MockeryTestCase`](library/Mockery/Adapter/Phpunit/MockeryTestCase.php)
|
|
|
40 |
class instead of `PHPUnit\Framework\TestCase`, or if you are already using a
|
|
|
41 |
custom base class for your tests, take a look at the traits available in the
|
|
|
42 |
[`Mockery\Adapter\Phpunit`](library/Mockery/Adapter/Phpunit) namespace.
|
|
|
43 |
|
|
|
44 |
## Test Doubles
|
|
|
45 |
|
|
|
46 |
Test doubles (often called mocks) simulate the behaviour of real objects. They are
|
|
|
47 |
commonly utilised to offer test isolation, to stand in for objects which do not
|
|
|
48 |
yet exist, or to allow for the exploratory design of class APIs without
|
|
|
49 |
requiring actual implementation up front.
|
|
|
50 |
|
|
|
51 |
The benefits of a test double framework are to allow for the flexible generation
|
|
|
52 |
and configuration of test doubles. They allow the setting of expected method calls
|
|
|
53 |
and/or return values using a flexible API which is capable of capturing every
|
|
|
54 |
possible real object behaviour in way that is stated as close as possible to a
|
|
|
55 |
natural language description. Use the `Mockery::mock` method to create a test
|
|
|
56 |
double.
|
|
|
57 |
|
|
|
58 |
``` php
|
|
|
59 |
$double = Mockery::mock();
|
|
|
60 |
```
|
|
|
61 |
|
|
|
62 |
If you need Mockery to create a test double to satisfy a particular type hint,
|
|
|
63 |
you can pass the type to the `mock` method.
|
|
|
64 |
|
|
|
65 |
``` php
|
|
|
66 |
class Book {}
|
|
|
67 |
|
|
|
68 |
interface BookRepository {
|
|
|
69 |
function find($id): Book;
|
|
|
70 |
function findAll(): array;
|
|
|
71 |
function add(Book $book): void;
|
|
|
72 |
}
|
|
|
73 |
|
|
|
74 |
$double = Mockery::mock(BookRepository::class);
|
|
|
75 |
```
|
|
|
76 |
|
|
|
77 |
A detailed explanation of creating and working with test doubles is given in the
|
|
|
78 |
documentation, [Creating test doubles](http://docs.mockery.io/en/latest/reference/creating_test_doubles.html)
|
|
|
79 |
section.
|
|
|
80 |
|
|
|
81 |
## Method Stubs 🎫
|
|
|
82 |
|
|
|
83 |
A method stub is a mechanism for having your test double return canned responses
|
|
|
84 |
to certain method calls. With stubs, you don't care how many times, if at all,
|
|
|
85 |
the method is called. Stubs are used to provide indirect input to the system
|
|
|
86 |
under test.
|
|
|
87 |
|
|
|
88 |
``` php
|
|
|
89 |
$double->allows()->find(123)->andReturns(new Book());
|
|
|
90 |
|
|
|
91 |
$book = $double->find(123);
|
|
|
92 |
```
|
|
|
93 |
|
|
|
94 |
If you have used Mockery before, you might see something new in the example
|
|
|
95 |
above — we created a method stub using `allows`, instead of the "old"
|
|
|
96 |
`shouldReceive` syntax. This is a new feature of Mockery v1, but fear not,
|
|
|
97 |
the trusty ol' `shouldReceive` is still here.
|
|
|
98 |
|
|
|
99 |
For new users of Mockery, the above example can also be written as:
|
|
|
100 |
|
|
|
101 |
``` php
|
|
|
102 |
$double->shouldReceive('find')->with(123)->andReturn(new Book());
|
|
|
103 |
$book = $double->find(123);
|
|
|
104 |
```
|
|
|
105 |
|
|
|
106 |
If your stub doesn't require specific arguments, you can also use this shortcut
|
|
|
107 |
for setting up multiple calls at once:
|
|
|
108 |
|
|
|
109 |
``` php
|
|
|
110 |
$double->allows([
|
|
|
111 |
"findAll" => [new Book(), new Book()],
|
|
|
112 |
]);
|
|
|
113 |
```
|
|
|
114 |
|
|
|
115 |
or
|
|
|
116 |
|
|
|
117 |
``` php
|
|
|
118 |
$double->shouldReceive('findAll')
|
|
|
119 |
->andReturn([new Book(), new Book()]);
|
|
|
120 |
```
|
|
|
121 |
|
|
|
122 |
You can also use this shortcut, which creates a double and sets up some stubs in
|
|
|
123 |
one call:
|
|
|
124 |
|
|
|
125 |
``` php
|
|
|
126 |
$double = Mockery::mock(BookRepository::class, [
|
|
|
127 |
"findAll" => [new Book(), new Book()],
|
|
|
128 |
]);
|
|
|
129 |
```
|
|
|
130 |
|
|
|
131 |
## Method Call Expectations 📲
|
|
|
132 |
|
|
|
133 |
A Method call expectation is a mechanism to allow you to verify that a
|
|
|
134 |
particular method has been called. You can specify the parameters and you can
|
|
|
135 |
also specify how many times you expect it to be called. Method call expectations
|
|
|
136 |
are used to verify indirect output of the system under test.
|
|
|
137 |
|
|
|
138 |
``` php
|
|
|
139 |
$book = new Book();
|
|
|
140 |
|
|
|
141 |
$double = Mockery::mock(BookRepository::class);
|
|
|
142 |
$double->expects()->add($book);
|
|
|
143 |
```
|
|
|
144 |
|
|
|
145 |
During the test, Mockery accept calls to the `add` method as prescribed.
|
|
|
146 |
After you have finished exercising the system under test, you need to
|
|
|
147 |
tell Mockery to check that the method was called as expected, using the
|
|
|
148 |
`Mockery::close` method. One way to do that is to add it to your `tearDown`
|
|
|
149 |
method in PHPUnit.
|
|
|
150 |
|
|
|
151 |
``` php
|
|
|
152 |
|
|
|
153 |
public function tearDown()
|
|
|
154 |
{
|
|
|
155 |
Mockery::close();
|
|
|
156 |
}
|
|
|
157 |
```
|
|
|
158 |
|
|
|
159 |
The `expects()` method automatically sets up an expectation that the method call
|
|
|
160 |
(and matching parameters) is called **once and once only**. You can choose to change
|
|
|
161 |
this if you are expecting more calls.
|
|
|
162 |
|
|
|
163 |
``` php
|
|
|
164 |
$double->expects()->add($book)->twice();
|
|
|
165 |
```
|
|
|
166 |
|
|
|
167 |
If you have used Mockery before, you might see something new in the example
|
|
|
168 |
above — we created a method expectation using `expects`, instead of the "old"
|
|
|
169 |
`shouldReceive` syntax. This is a new feature of Mockery v1, but same as with
|
|
|
170 |
`accepts` in the previous section, it can be written in the "old" style.
|
|
|
171 |
|
|
|
172 |
For new users of Mockery, the above example can also be written as:
|
|
|
173 |
|
|
|
174 |
``` php
|
|
|
175 |
$double->shouldReceive('find')
|
|
|
176 |
->with(123)
|
|
|
177 |
->once()
|
|
|
178 |
->andReturn(new Book());
|
|
|
179 |
$book = $double->find(123);
|
|
|
180 |
```
|
|
|
181 |
|
|
|
182 |
A detailed explanation of declaring expectations on method calls, please
|
|
|
183 |
read the documentation, the [Expectation declarations](http://docs.mockery.io/en/latest/reference/expectations.html)
|
|
|
184 |
section. After that, you can also learn about the new `allows` and `expects` methods
|
|
|
185 |
in the [Alternative shouldReceive syntax](http://docs.mockery.io/en/latest/reference/alternative_should_receive_syntax.html)
|
|
|
186 |
section.
|
|
|
187 |
|
|
|
188 |
It is worth mentioning that one way of setting up expectations is no better or worse
|
|
|
189 |
than the other. Under the hood, `allows` and `expects` are doing the same thing as
|
|
|
190 |
`shouldReceive`, at times in "less words", and as such it comes to a personal preference
|
|
|
191 |
of the programmer which way to use.
|
|
|
192 |
|
|
|
193 |
## Test Spies 🕵ï¸
|
|
|
194 |
|
|
|
195 |
By default, all test doubles created with the `Mockery::mock` method will only
|
|
|
196 |
accept calls that they have been configured to `allow` or `expect` (or in other words,
|
|
|
197 |
calls that they `shouldReceive`). Sometimes we don't necessarily care about all of the
|
|
|
198 |
calls that are going to be made to an object. To facilitate this, we can tell Mockery
|
|
|
199 |
to ignore any calls it has not been told to expect or allow. To do so, we can tell a
|
|
|
200 |
test double `shouldIgnoreMissing`, or we can create the double using the `Mocker::spy`
|
|
|
201 |
shortcut.
|
|
|
202 |
|
|
|
203 |
``` php
|
|
|
204 |
// $double = Mockery::mock()->shouldIgnoreMissing();
|
|
|
205 |
$double = Mockery::spy();
|
|
|
206 |
|
|
|
207 |
$double->foo(); // null
|
|
|
208 |
$double->bar(); // null
|
|
|
209 |
```
|
|
|
210 |
|
|
|
211 |
Further to this, sometimes we want to have the object accept any call during the test execution
|
|
|
212 |
and then verify the calls afterwards. For these purposes, we need our test
|
|
|
213 |
double to act as a Spy. All mockery test doubles record the calls that are made
|
|
|
214 |
to them for verification afterwards by default:
|
|
|
215 |
|
|
|
216 |
``` php
|
|
|
217 |
$double->baz(123);
|
|
|
218 |
|
|
|
219 |
$double->shouldHaveReceived()->baz(123); // null
|
|
|
220 |
$double->shouldHaveReceived()->baz(12345); // Uncaught Exception Mockery\Exception\InvalidCountException...
|
|
|
221 |
```
|
|
|
222 |
|
|
|
223 |
Please refer to the [Spies](http://docs.mockery.io/en/latest/reference/spies.html) section
|
|
|
224 |
of the documentation to learn more about the spies.
|
|
|
225 |
|
|
|
226 |
## Utilities 🔌
|
|
|
227 |
|
|
|
228 |
### Global Helpers
|
|
|
229 |
|
|
|
230 |
Mockery ships with a handful of global helper methods, you just need to ask
|
|
|
231 |
Mockery to declare them.
|
|
|
232 |
|
|
|
233 |
``` php
|
|
|
234 |
Mockery::globalHelpers();
|
|
|
235 |
|
|
|
236 |
$mock = mock(Some::class);
|
|
|
237 |
$spy = spy(Some::class);
|
|
|
238 |
|
|
|
239 |
$spy->shouldHaveReceived()
|
|
|
240 |
->foo(anyArgs());
|
|
|
241 |
```
|
|
|
242 |
|
|
|
243 |
All of the global helpers are wrapped in a `!function_exists` call to avoid
|
|
|
244 |
conflicts. So if you already have a global function called `spy`, Mockery will
|
|
|
245 |
silently skip the declaring its own `spy` function.
|
|
|
246 |
|
|
|
247 |
### Testing Traits
|
|
|
248 |
|
|
|
249 |
As Mockery ships with code generation capabilities, it was trivial to add
|
|
|
250 |
functionality allowing users to create objects on the fly that use particular
|
|
|
251 |
traits. Any abstract methods defined by the trait will be created and can have
|
|
|
252 |
expectations or stubs configured like normal Test Doubles.
|
|
|
253 |
|
|
|
254 |
``` php
|
|
|
255 |
trait Foo {
|
|
|
256 |
function foo() {
|
|
|
257 |
return $this->doFoo();
|
|
|
258 |
}
|
|
|
259 |
|
|
|
260 |
abstract function doFoo();
|
|
|
261 |
}
|
|
|
262 |
|
|
|
263 |
$double = Mockery::mock(Foo::class);
|
|
|
264 |
$double->allows()->doFoo()->andReturns(123);
|
|
|
265 |
$double->foo(); // int(123)
|
|
|
266 |
```
|
|
|
267 |
|
|
|
268 |
## Versioning
|
|
|
269 |
|
|
|
270 |
The Mockery team attempts to adhere to [Semantic Versioning](http://semver.org),
|
|
|
271 |
however, some of Mockery's internals are considered private and will be open to
|
|
|
272 |
change at any time. Just because a class isn't final, or a method isn't marked
|
|
|
273 |
private, does not mean it constitutes part of the API we guarantee under the
|
|
|
274 |
versioning scheme.
|
|
|
275 |
|
|
|
276 |
### Alternative Runtimes
|
|
|
277 |
|
|
|
278 |
Mockery 1.3 was the last version to support HHVM 3 and PHP 5. There is no support for HHVM 4+.
|
|
|
279 |
|
|
|
280 |
## A new home for Mockery
|
|
|
281 |
|
|
|
282 |
⚠️️ Update your remotes! Mockery has transferred to a new location. While it was once
|
|
|
283 |
at `padraic/mockery`, it is now at `mockery/mockery`. While your
|
|
|
284 |
existing repositories will redirect transparently for any operations, take some
|
|
|
285 |
time to transition to the new URL.
|
|
|
286 |
```sh
|
|
|
287 |
$ git remote set-url upstream https://github.com/mockery/mockery.git
|
|
|
288 |
```
|
|
|
289 |
Replace `upstream` with the name of the remote you use locally; `upstream` is commonly
|
|
|
290 |
used but you may be using something else. Run `git remote -v` to see what you're actually
|
|
|
291 |
using.
|