@@ -3,18 +3,69 @@ Specify
3
3
4
4
BDD style code blocks for PHPUnit / Codeception
5
5
6
+ [ ![ Latest Stable Version] ( https://poser.pugx.org/codeception/specify/v/stable )] ( https://packagist.org/packages/codeception/specify ) [ ![ Total Downloads] ( https://poser.pugx.org/codeception/specify/downloads )] ( https://packagist.org/packages/codeception/specify ) [ ![ Latest Unstable Version] ( https://poser.pugx.org/codeception/specify/v/unstable )] ( https://packagist.org/packages/codeception/specify ) [ ![ License] ( https://poser.pugx.org/codeception/specify/license )] ( https://packagist.org/packages/codeception/specify )
7
+
6
8
Specify allows you to write your tests in more readable BDD style, the same way you might have experienced with [ Jasmine] ( https://jasmine.github.io/ ) .
7
9
Inspired by MiniTest of Ruby now you combine BDD and classical TDD style in one test.
8
10
9
- [ ![ Build Status ] ( https://travis-ci.org/Codeception/Specify.png?branch=master )] ( https://travis-ci.org/Codeception/Specify ) [ ![ Latest Stable Version ] ( https://poser.pugx.org/codeception/specify/v/stable.png )] ( https://packagist.org/packages/codeception/specify )
11
+ ### BDD Example
10
12
11
- Additionaly, we recommend to combine this with [ ** Codeception/Verify ** ] ( https://github.com/Codeception/Verify ) library, to get BDD style assertions.
13
+ Specify supports ` describe-it ` BDD syntax inside PHPUnit
12
14
13
- ``` php
15
+ ``` php
14
16
<?php
15
- class UserTest extends PHPUnit_Framework_TestCase {
17
+ class UserTest extends PHPUnit\Framework\TestCase {
16
18
17
19
use Codeception\Specify;
20
+
21
+ /** @specify */
22
+ protected $user;
23
+
24
+ public function setUp()
25
+ {
26
+ $this->user = new User;
27
+ }
28
+
29
+ public function testValidation()
30
+ {
31
+ $this->describe("user", function() {
32
+ $this->it("should have a name", function() {
33
+ $this->user->username = null;
34
+ $this->assertFalse($this->user->validate(['username']));
35
+ });
36
+
37
+ $this->it("should not have long name", function() {
38
+ $this->user->username = 'toolooooongnaaaaaaameeee';
39
+ $this->assertFalse($this->user->validate(['username']));
40
+ });
41
+
42
+ // use `$this->>should` as shortcut
43
+ $this->should("be ok with valid name", function() {
44
+ $this->user->username = 'davert';
45
+ $this->assertTrue($this->user->validate(['username']));
46
+ });
47
+
48
+ // empty codeblocks are marked as Incomplete tests
49
+ $this->it("should be ok with valid name");
50
+ });
51
+
52
+ }
53
+ }
54
+ ```
55
+
56
+ ### Basic Example
57
+
58
+ Traditionally Specify used ` $this->specify ` function for all descriptions.
59
+ That works too!
60
+
61
+ ``` php
62
+ <?php
63
+ class UserTest extends PHPUnit\Framework\TestCase {
64
+
65
+ use Codeception\Specify;
66
+
67
+ /** @specify */
68
+ protected $user;
18
69
19
70
public function setUp()
20
71
{
@@ -27,32 +78,31 @@ class UserTest extends PHPUnit_Framework_TestCase {
27
78
28
79
$this->specify("username is required", function() {
29
80
$this->user->username = null;
30
- verify ($this->user->validate(['username'])->false( ));
81
+ $this->assertFalse ($this->user->validate(['username']));
31
82
});
32
83
33
84
$this->specify("username is too long", function() {
34
85
$this->user->username = 'toolooooongnaaaaaaameeee',
35
- verify ($this->user->validate(['username'])->false( ));
86
+ $this->assertFalse ($this->user->validate(['username']));
36
87
});
37
88
38
- // alternative, TDD assertions can be used too.
39
89
$this->specify("username is ok", function() {
40
90
$this->user->username = 'davert',
41
91
$this->assertTrue($this->user->validate(['username']));
42
92
});
43
93
}
44
94
}
45
- ?>
46
95
```
47
96
97
+
48
98
## Purpose
49
99
50
- This tiny library makes your tests a bit readable, by orginizing test in well described code blocks.
100
+ This tiny library makes your tests a bit readable, by organizing test in well described code blocks.
51
101
Each code block is isolated.
52
102
53
- This means call to ` $this->specify ` does not affect any instance variable of a test class.
103
+ This means call to ` $this->specify ` does not change values of configured properties of a test class.
54
104
55
- ``` php
105
+ ``` php
56
106
<?php
57
107
$this->user->name = 'davert';
58
108
$this->specify("i can change my name", function() {
@@ -66,7 +116,7 @@ $this->assertEquals('davert', $this->user->name);
66
116
67
117
Failure in ` specify ` block won't get your test stopped.
68
118
69
- ``` php
119
+ ``` php
70
120
<?php
71
121
$this->specify("failing but test goes on", function() {
72
122
$this->fail('bye');
@@ -82,107 +132,92 @@ If a test fails you will see specification text in the result.
82
132
## Isolation
83
133
84
134
Isolation is achieved by ** cloning object properties** for each specify block.
85
- By default objects are cloned using deep cloning method.
86
- This behavior can be customized in order to speed up test execution by preventing some objects from cloning or switching to shallow cloning using ` clone ` operator.
87
- Some properties can be ignored from cloning using either global or local config settings.
88
-
89
- ### Global Configuration
90
-
91
- Cloning configuration can be set globally
135
+ Only properties makred with ` @specify ` annotation are cloned.
92
136
93
137
``` php
94
- <?php
95
- // globally disabling cloning of properties
96
- Codeception\Specify\Config::setIgnoredProperties(['user', 'repository']);
97
- ?>
98
- ```
138
+ /** @specify */
139
+ protected $user; // cloning
99
140
100
- See complete [ reference] ( https://github.com/Codeception/Specify/blob/master/docs/GlobalConfig.md ) .
141
+ /**
142
+ * @specify
143
+ **/
144
+ protected $user; // cloning
101
145
102
- ### Local Configuration
146
+ protected $repository; // not cloning
147
+ ```
103
148
104
- Configuring can be done locally per test case
149
+ Objects are cloned using deep cloning method.
150
+ ** If object cloning affects performance, consider turning the clonning off** .
105
151
106
- ``` php
107
- <?php
108
- class UserTest extends \PHPUnit_Framework_TestCase
109
- {
110
- use Codeception\Specify;
111
-
112
- function testUser()
113
- {
114
- // do not deep clone user property
115
- $this->specifyConfig()
116
- ->shallowClone('user');
117
- }
118
- }
119
- ```
152
+ ** Mocks are isolated** by default.
120
153
121
- Only specific properties can be preserved in specify blocks:
154
+ A mock defined inside a specify block won't be executed inside an outer test,
155
+ and mock from outer test won't be triggered inside codeblock.
122
156
123
157
``` php
124
158
<?php
125
- class UserTest extends \PHPUnit_Framework_TestCase
126
- {
127
- use Codeception\Specify;
128
- protected $user;
129
- protected $post;
159
+ $config = $this->createMock(Config::class);
160
+ $config->expects($this->once())->method('init');
130
161
131
- function testUser()
132
- {
133
- $this->user = 'davert';
134
- $this->post = 'hello world';
162
+ $config->init();
163
+ // success: $config->init() was executed
135
164
136
- $this->specifyConfig()
137
- ->cloneOnly('user');
165
+ $this->specify('this should not fail', function () {
166
+ $config = $this->createMock(Config::class);
167
+ $config->expects($this->never())->method('init')->willReturn(null);
168
+ // success: $config->init() is never executed
169
+ });
138
170
139
- $this->specify('post is not cloned', function() {
140
- $this->user = 'john';
141
- $this->post = 'bye world';
142
- });
143
- $this->assertEquals('davert', $this->user); // user is restored
144
- $this->assertEquals('bye world', $this->post); // post was not stored
145
- }
146
- }
147
171
```
148
172
149
-
150
- [ Reference] ( https://github.com/Codeception/Specify/blob/master/docs/LocalConfig.md )
151
-
152
-
153
- ## Exceptions
154
-
155
-
156
173
## Examples
157
174
158
- DataProviders alternative. Quite useful for basic data providers.
175
+ DataProviders alternative
159
176
160
- ``` php
177
+ ``` php
161
178
<?php
162
179
$this->specify("should calculate square numbers", function($number, $square) {
163
180
$this->assertEquals($square, $number*$number);
164
181
}, ['examples' => [
165
182
[2,4],
166
183
[3,9]
167
184
]]);
168
- ?>
169
185
```
170
186
171
187
You can also use DataProvider functions in ` examples ` param.
172
188
173
- ``` php
189
+ ``` php
174
190
<?php
175
191
$this->specify("should calculate square numbers", function($number, $square) {
176
192
$this->assertEquals($square, $number*$number);
177
193
}, ['examples' => $this->provider()]);
178
- ?>
194
+ ```
195
+
196
+ Can also be used with real data providers:
197
+
198
+ ``` php
199
+ <?php
200
+ /**
201
+ * @dataProvider someData
202
+ */
203
+ public function testExamplesAndDataProvider($param)
204
+ {
205
+ $this->specify('should assert data provider', function ($example) use ($param) {
206
+ $this->assertGreaterThanOrEqual(5, $param + $example);
207
+ }, ['examples' => [[4], [7], [5]]]);
208
+ }
209
+
210
+ public function someData()
211
+ {
212
+ return [[1], [2]];
213
+ }
179
214
```
180
215
181
216
## Before/After
182
217
183
218
There are also before and after callbacks, which act as setUp/tearDown but only for specify.
184
219
185
- ``` php
220
+ ``` php
186
221
<?php
187
222
$this->beforeSpecify(function() {
188
223
// prepare something;
@@ -194,9 +229,19 @@ $this->cleanSpecify(); // removes before/after callbacks
194
229
?>
195
230
```
196
231
232
+ ## API
233
+
234
+ Available methods:
235
+
236
+ * ` $this->specify(name, callable fn = null, params = []) ` - starts a specify code block. If ` fn ` is null, marks test as incomplete.
237
+ * ` $this->describe(name, callable fn = null) ` - starts a describe code block. Same as ` specify ` but expects to receive more nested into ` fn ` .
238
+ * ` $this->it(name, callable fn = null) ` - starts a code block. Alias to ` specify ` .
239
+ * ` $this->should(name, callable fn = null) ` - starts a code block. Same as ` specify ` but prepends word "should" into description.
240
+
241
+
197
242
## Installation
198
243
199
- * Requires PHP >= 5.4 .*
244
+ * Requires PHP >= 7 .*
200
245
201
246
Install with Composer:
202
247
@@ -208,7 +253,12 @@ Install with Composer:
208
253
209
254
}
210
255
```
211
- Include ` Codeception\Specify ` trait into your test.
256
+ Include ` Codeception\Specify ` trait into ` PHPUnit\Framework\TestCase ` .
257
+
258
+ ## Recommended
212
259
260
+ * Use [ Codeception/AssertThrows] ( https://github.com/Codeception/AssertThrows ) for exception assertions
261
+ * Use [ Codeceptoin/DomainAssert] ( https://github.com/Codeception/DomainAssert ) for verbose domain logic assertions
262
+ * Сombine this with [ Codeception/Verify] ( https://github.com/Codeception/Verify ) library, to get BDD style assertions.
213
263
214
264
License: MIT
0 commit comments