@@ -3,18 +3,69 @@ Specify
33
44BDD style code blocks for PHPUnit / Codeception
55
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+
68Specify allows you to write your tests in more readable BDD style, the same way you might have experienced with [ Jasmine] ( https://jasmine.github.io/ ) .
79Inspired by MiniTest of Ruby now you combine BDD and classical TDD style in one test.
810
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
1012
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
1214
13- ``` php
15+ ``` php
1416<?php
15- class UserTest extends PHPUnit_Framework_TestCase {
17+ class UserTest extends PHPUnit\Framework\TestCase {
1618
1719 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;
1869
1970 public function setUp()
2071 {
@@ -27,32 +78,31 @@ class UserTest extends PHPUnit_Framework_TestCase {
2778
2879 $this->specify("username is required", function() {
2980 $this->user->username = null;
30- verify ($this->user->validate(['username'])->false( ));
81+ $this->assertFalse ($this->user->validate(['username']));
3182 });
3283
3384 $this->specify("username is too long", function() {
3485 $this->user->username = 'toolooooongnaaaaaaameeee',
35- verify ($this->user->validate(['username'])->false( ));
86+ $this->assertFalse ($this->user->validate(['username']));
3687 });
3788
38- // alternative, TDD assertions can be used too.
3989 $this->specify("username is ok", function() {
4090 $this->user->username = 'davert',
4191 $this->assertTrue($this->user->validate(['username']));
4292 });
4393 }
4494}
45- ?>
4695```
4796
97+
4898## Purpose
4999
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.
51101Each code block is isolated.
52102
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.
54104
55- ``` php
105+ ``` php
56106<?php
57107$this->user->name = 'davert';
58108$this->specify("i can change my name", function() {
@@ -66,7 +116,7 @@ $this->assertEquals('davert', $this->user->name);
66116
67117Failure in ` specify ` block won't get your test stopped.
68118
69- ``` php
119+ ``` php
70120<?php
71121$this->specify("failing but test goes on", function() {
72122 $this->fail('bye');
@@ -82,107 +132,92 @@ If a test fails you will see specification text in the result.
82132## Isolation
83133
84134Isolation 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.
92136
93137``` php
94- <?php
95- // globally disabling cloning of properties
96- Codeception\Specify\Config::setIgnoredProperties(['user', 'repository']);
97- ?>
98- ```
138+ /** @specify */
139+ protected $user; // cloning
99140
100- See complete [ reference] ( https://github.com/Codeception/Specify/blob/master/docs/GlobalConfig.md ) .
141+ /**
142+ * @specify
143+ **/
144+ protected $user; // cloning
101145
102- ### Local Configuration
146+ protected $repository; // not cloning
147+ ```
103148
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** .
105151
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.
120153
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.
122156
123157``` php
124158<?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');
130161
131- function testUser()
132- {
133- $this->user = 'davert';
134- $this->post = 'hello world';
162+ $config->init();
163+ // success: $config->init() was executed
135164
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+ });
138170
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- }
147171```
148172
149-
150- [ Reference] ( https://github.com/Codeception/Specify/blob/master/docs/LocalConfig.md )
151-
152-
153- ## Exceptions
154-
155-
156173## Examples
157174
158- DataProviders alternative. Quite useful for basic data providers.
175+ DataProviders alternative
159176
160- ``` php
177+ ``` php
161178<?php
162179$this->specify("should calculate square numbers", function($number, $square) {
163180 $this->assertEquals($square, $number*$number);
164181}, ['examples' => [
165182 [2,4],
166183 [3,9]
167184]]);
168- ?>
169185```
170186
171187You can also use DataProvider functions in ` examples ` param.
172188
173- ``` php
189+ ``` php
174190<?php
175191$this->specify("should calculate square numbers", function($number, $square) {
176192 $this->assertEquals($square, $number*$number);
177193}, ['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+ }
179214```
180215
181216## Before/After
182217
183218There are also before and after callbacks, which act as setUp/tearDown but only for specify.
184219
185- ``` php
220+ ``` php
186221<?php
187222$this->beforeSpecify(function() {
188223 // prepare something;
@@ -194,9 +229,19 @@ $this->cleanSpecify(); // removes before/after callbacks
194229?>
195230```
196231
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+
197242## Installation
198243
199- * Requires PHP >= 5.4 .*
244+ * Requires PHP >= 7 .*
200245
201246Install with Composer:
202247
@@ -208,7 +253,12 @@ Install with Composer:
208253
209254}
210255```
211- Include ` Codeception\Specify ` trait into your test.
256+ Include ` Codeception\Specify ` trait into ` PHPUnit\Framework\TestCase ` .
257+
258+ ## Recommended
212259
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.
213263
214264License: MIT
0 commit comments