minispec 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.pryrc +2 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +2140 -0
- data/Rakefile +11 -0
- data/bin/minispec +4 -0
- data/lib/minispec.rb +175 -0
- data/lib/minispec/api.rb +2 -0
- data/lib/minispec/api/class.rb +195 -0
- data/lib/minispec/api/class/after.rb +49 -0
- data/lib/minispec/api/class/around.rb +54 -0
- data/lib/minispec/api/class/before.rb +101 -0
- data/lib/minispec/api/class/helpers.rb +116 -0
- data/lib/minispec/api/class/let.rb +44 -0
- data/lib/minispec/api/class/tests.rb +33 -0
- data/lib/minispec/api/instance.rb +158 -0
- data/lib/minispec/api/instance/mocks/doubles.rb +36 -0
- data/lib/minispec/api/instance/mocks/mocks.rb +319 -0
- data/lib/minispec/api/instance/mocks/spies.rb +17 -0
- data/lib/minispec/api/instance/mocks/stubs.rb +105 -0
- data/lib/minispec/helpers.rb +1 -0
- data/lib/minispec/helpers/array.rb +56 -0
- data/lib/minispec/helpers/booleans.rb +108 -0
- data/lib/minispec/helpers/generic.rb +24 -0
- data/lib/minispec/helpers/mocks/expectations.rb +29 -0
- data/lib/minispec/helpers/mocks/spies.rb +36 -0
- data/lib/minispec/helpers/raise.rb +44 -0
- data/lib/minispec/helpers/throw.rb +29 -0
- data/lib/minispec/mocks.rb +11 -0
- data/lib/minispec/mocks/expectations.rb +77 -0
- data/lib/minispec/mocks/stubs.rb +178 -0
- data/lib/minispec/mocks/validations.rb +80 -0
- data/lib/minispec/mocks/validations/amount.rb +63 -0
- data/lib/minispec/mocks/validations/arguments.rb +161 -0
- data/lib/minispec/mocks/validations/caller.rb +43 -0
- data/lib/minispec/mocks/validations/order.rb +47 -0
- data/lib/minispec/mocks/validations/raise.rb +111 -0
- data/lib/minispec/mocks/validations/return.rb +74 -0
- data/lib/minispec/mocks/validations/throw.rb +91 -0
- data/lib/minispec/mocks/validations/yield.rb +141 -0
- data/lib/minispec/proxy.rb +201 -0
- data/lib/minispec/reporter.rb +185 -0
- data/lib/minispec/utils.rb +139 -0
- data/lib/minispec/utils/differ.rb +325 -0
- data/lib/minispec/utils/pretty_print.rb +51 -0
- data/lib/minispec/utils/raise.rb +123 -0
- data/lib/minispec/utils/throw.rb +140 -0
- data/minispec.gemspec +27 -0
- data/test/mocks/expectations/amount.rb +67 -0
- data/test/mocks/expectations/arguments.rb +126 -0
- data/test/mocks/expectations/caller.rb +55 -0
- data/test/mocks/expectations/generic.rb +35 -0
- data/test/mocks/expectations/order.rb +46 -0
- data/test/mocks/expectations/raise.rb +166 -0
- data/test/mocks/expectations/return.rb +71 -0
- data/test/mocks/expectations/throw.rb +113 -0
- data/test/mocks/expectations/yield.rb +109 -0
- data/test/mocks/spies/amount.rb +68 -0
- data/test/mocks/spies/arguments.rb +57 -0
- data/test/mocks/spies/generic.rb +61 -0
- data/test/mocks/spies/order.rb +38 -0
- data/test/mocks/spies/raise.rb +158 -0
- data/test/mocks/spies/return.rb +71 -0
- data/test/mocks/spies/throw.rb +113 -0
- data/test/mocks/spies/yield.rb +101 -0
- data/test/mocks/test__doubles.rb +98 -0
- data/test/mocks/test__expectations.rb +27 -0
- data/test/mocks/test__mocks.rb +197 -0
- data/test/mocks/test__proxies.rb +61 -0
- data/test/mocks/test__spies.rb +43 -0
- data/test/mocks/test__stubs.rb +427 -0
- data/test/proxified_asserts.rb +34 -0
- data/test/setup.rb +53 -0
- data/test/test__around.rb +58 -0
- data/test/test__assert.rb +510 -0
- data/test/test__before_and_after.rb +117 -0
- data/test/test__before_and_after_all.rb +71 -0
- data/test/test__helpers.rb +197 -0
- data/test/test__raise.rb +104 -0
- data/test/test__skip.rb +41 -0
- data/test/test__throw.rb +103 -0
- metadata +196 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2973847800ef2aac6fb86844541a766d114aa04c
|
4
|
+
data.tar.gz: 3674b9c2392225cdd50768fd13de39563534c583
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6eb0c4d0ca16fff824fa9d249baf8a9cf14c166dee42955a3bc9242b5843922d2ee9547eda4a40781dead96775f51223f1f939fac9d01abda2f0a2b94fe97bf9
|
7
|
+
data.tar.gz: 610910d94d916f251c542c2f470e6b3c52650a913311cf6d5f79285350c1083b60ce083bdab08991b63e5ab7e4a1feed54b91f12bb98738416bc4d921086a90f
|
data/.pryrc
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Slee Woo <mail@sleewoo.com>
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,2140 @@
|
|
1
|
+
|
2
|
+
### Minispec
|
3
|
+
|
4
|
+
**Simple, Intuitive, Full-featured Testing Framework**
|
5
|
+
|
6
|
+
[Install](#install) |
|
7
|
+
[Quick Start](#quick-start) |
|
8
|
+
[Docs](#docs) |
|
9
|
+
[Contributors](#contributors) |
|
10
|
+
[Authors and License](#license)
|
11
|
+
|
12
|
+
## What and Why
|
13
|
+
|
14
|
+
Simply i tired of syntax like `assert_equal(b, a)`, `a.should == b` and `expect(a).to eq(b)` etc.
|
15
|
+
|
16
|
+
`is(a) == b` is all i want to type.
|
17
|
+
|
18
|
+
Also i tired to learn framework specific techniques. I want simply to use Ruby's native methods:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
is(a) == b
|
22
|
+
does(a).include?(b)
|
23
|
+
is(a).empty?
|
24
|
+
```
|
25
|
+
|
26
|
+
`==`, `include?`, `empty?` are all Ruby methods called on `a`.
|
27
|
+
|
28
|
+
What you see around `a` is a simple wrapper that passes messages to `a` and mark the assertion as passed or failed, depending on returned value.
|
29
|
+
|
30
|
+
|
31
|
+
## Install
|
32
|
+
|
33
|
+
Add this line to your application's Gemfile:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
gem 'minispec'
|
37
|
+
```
|
38
|
+
|
39
|
+
And then execute:
|
40
|
+
|
41
|
+
```bash
|
42
|
+
$ bundle
|
43
|
+
```
|
44
|
+
|
45
|
+
Or install it yourself as:
|
46
|
+
|
47
|
+
```bash
|
48
|
+
$ gem install minispec
|
49
|
+
```
|
50
|
+
|
51
|
+
then load it using `require 'minispec'`
|
52
|
+
|
53
|
+
|
54
|
+
## Quick Start
|
55
|
+
|
56
|
+
*Examples borrowed from [github.com/rubyspec](https://github.com/rubyspec/rubyspec). Commented are the original assertions.*
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
describe "Array.allocate" do
|
60
|
+
it "returns an instance of Array" do
|
61
|
+
ary = Array.allocate
|
62
|
+
# ary.should be_an_instance_of(Array)
|
63
|
+
is(ary).instance_of?(Array)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "returns a fully-formed instance of Array" do
|
67
|
+
ary = Array.allocate
|
68
|
+
# ary.size.should == 0
|
69
|
+
assert(ary.size) == 0
|
70
|
+
ary << 1
|
71
|
+
# ary.should == [1]
|
72
|
+
assert(ary) == [1]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "does not accept any arguments" do
|
76
|
+
# lambda { Array.allocate(1) }.should raise_error(ArgumentError)
|
77
|
+
does { Array.allocate(1) }.raise?(ArgumentError)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
|
83
|
+
# Docs
|
84
|
+
|
85
|
+
* [Defining Specs](#defining-specs)
|
86
|
+
* [Nested Specs](#-nested-specs)
|
87
|
+
* [Defining Tests](#defining-tests)
|
88
|
+
* [Skipping a test](#-skipping-a-test)
|
89
|
+
* [Mark a test as failed](#-mark-a-test-as-failed)
|
90
|
+
* [Shared examples and setups](#shared-examples-and-setups)
|
91
|
+
* [Resetting included resources](#-resetting-included-resources)
|
92
|
+
* [Local variables and subject](#local-variables-and-subject)
|
93
|
+
* [Custom error messages](#custom-error-messages)
|
94
|
+
* [Hooks](#hooks)
|
95
|
+
* [`before` and `before_all`](#-before-and-before_all)
|
96
|
+
* [`after` and `after_all`](#-after-and-after_all)
|
97
|
+
* [`around` and `around_all`](#-around-and-around_all)
|
98
|
+
* [Filters](#-filters)
|
99
|
+
* [Assertions](#assertions)
|
100
|
+
* [Negative assertions](#-negative-assertions)
|
101
|
+
* [Semantic sugar](#-semantic-sugar)
|
102
|
+
* [Helpers](#helpers)
|
103
|
+
* [Built-in helpers](#-built-in-helpers)
|
104
|
+
* [raise](#-raise-helper)
|
105
|
+
* [throw](#-throw-helper)
|
106
|
+
* [boolean](#-boolean-helpers)
|
107
|
+
* [array](#-array-helpers)
|
108
|
+
* [silent](#-silent-helper)
|
109
|
+
* [Custom helpers](#-custom-helpers)
|
110
|
+
* [Helpers with blocks](#-helpers-with-blocks)
|
111
|
+
* [Helpers aliases](#-helpers-aliases)
|
112
|
+
* [Mocking](#mocking)
|
113
|
+
* [Expectations](#-expectations)
|
114
|
+
* [Constraints](#-constraints)
|
115
|
+
* [arguments](#-arguments)
|
116
|
+
* [returned value](#-returned-value)
|
117
|
+
* [raised exception](#-raised-exception)
|
118
|
+
* [thrown symbol](#-thrown-symbol)
|
119
|
+
* [yielded arguments](#-yielded-arguments)
|
120
|
+
* [messages amount](#-messages-amount)
|
121
|
+
* [messages order](#-messages-order)
|
122
|
+
* [Spies](#spies)
|
123
|
+
* [Stubs](#stubs)
|
124
|
+
* [Argument-vary stubs](#-argument-vary-stubs)
|
125
|
+
* [Stubbing multiple methods at once](#-stubbing-multiple-methods-at-once)
|
126
|
+
* [Chained stubs](#-chained-stubs)
|
127
|
+
* [Calling original](#-calling-original)
|
128
|
+
* [Stubs visibility](#-stubs-visibility)
|
129
|
+
* [Mocks](#mocks)
|
130
|
+
* [Doubles](#doubles)
|
131
|
+
* [Running Specs](#running-specs)
|
132
|
+
|
133
|
+
|
134
|
+
## Defining Specs
|
135
|
+
|
136
|
+
There are 2 ways to define Minispec specs: by using Minispec's DSL and by using Ruby classes.
|
137
|
+
|
138
|
+
Minispec's DSL has 3 methods that allow to define specs:
|
139
|
+
|
140
|
+
* `describe`
|
141
|
+
* `context`
|
142
|
+
* `section`
|
143
|
+
|
144
|
+
They accepts a single argument(the spec name) and a block containing setups and tests:
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
describe SomeClass do
|
148
|
+
# setups and tests
|
149
|
+
end
|
150
|
+
```
|
151
|
+
|
152
|
+
When using classes you should `include Minispec`:
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
class SomeSpec
|
156
|
+
include Minispec
|
157
|
+
# setups and tests
|
158
|
+
end
|
159
|
+
```
|
160
|
+
|
161
|
+
[⇧ Table of Contents](#docs)
|
162
|
+
|
163
|
+
|
164
|
+
### ↳ Nested Specs
|
165
|
+
|
166
|
+
Minispec allows to define unlimitedly nested specs using same `describe`/`context`/`section` DSL:
|
167
|
+
|
168
|
+
Nested specs are akin of valve, they inherits everything(except tests) from parent spec but share nothing with it and does not change parent state in any way:
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
describe :A do
|
172
|
+
before { @letter = 'A' }
|
173
|
+
|
174
|
+
# some tests
|
175
|
+
|
176
|
+
describe :B do
|
177
|
+
before { @letter = 'B' }
|
178
|
+
# it will run both inherited and own callbacks but wont change A's @letter
|
179
|
+
end
|
180
|
+
|
181
|
+
# @letter is still 'A'
|
182
|
+
end
|
183
|
+
```
|
184
|
+
|
185
|
+
|
186
|
+
[⇧ Table of Contents](#docs)
|
187
|
+
|
188
|
+
|
189
|
+
## Defining Tests
|
190
|
+
|
191
|
+
Here are the methods that can be used to define tests:
|
192
|
+
|
193
|
+
* `test`
|
194
|
+
* `testing`
|
195
|
+
* `example`
|
196
|
+
* `should`
|
197
|
+
* `it`
|
198
|
+
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
# spec
|
202
|
+
describe :RequestTest do
|
203
|
+
|
204
|
+
# test 1
|
205
|
+
should 'respond to #user_agent' do
|
206
|
+
request = Sinatra::Request.new({'HTTP_USER_AGENT' => 'Test'})
|
207
|
+
does(request).respond_to?(:user_agent)
|
208
|
+
assert(request.user_agent) == 'Test'
|
209
|
+
end
|
210
|
+
|
211
|
+
# test 2
|
212
|
+
it 'is secure when the url scheme is https' do
|
213
|
+
request = Sinatra::Request.new('rack.url_scheme' => 'https')
|
214
|
+
is(request).secure?
|
215
|
+
end
|
216
|
+
|
217
|
+
# test 3
|
218
|
+
testing 'it respects X-Forwarded-Proto header for proxied SSL' do
|
219
|
+
request = Sinatra::Request.new('HTTP_X_FORWARDED_PROTO' => 'https')
|
220
|
+
is(request).secure?
|
221
|
+
end
|
222
|
+
|
223
|
+
# test 4
|
224
|
+
it "exposes the preferred type's parameters" do
|
225
|
+
request = Sinatra::Request.new('HTTP_ACCEPT' => 'image/jpeg; compress=0.2')
|
226
|
+
assert(request.preferred_type.params) == { 'compress' => '0.2' }
|
227
|
+
end
|
228
|
+
|
229
|
+
# etc.
|
230
|
+
end
|
231
|
+
```
|
232
|
+
|
233
|
+
Tests can Not be defined inside another tests. If you need concerns separation use nested specs instead.
|
234
|
+
|
235
|
+
[⇧ Table of Contents](#docs)
|
236
|
+
|
237
|
+
|
238
|
+
### ↳ Skipping a test
|
239
|
+
|
240
|
+
When you need to skip some test simply use `skip` method inside test:
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
should 'work with new Hash syntax' do
|
244
|
+
skip if RUBY_VERSION < '1.9'
|
245
|
+
# code here wont be evaluated on Ruby 1.8
|
246
|
+
end
|
247
|
+
```
|
248
|
+
|
249
|
+
Any code after `skip` method will be just ignored and test reported as skipped.
|
250
|
+
|
251
|
+
|
252
|
+
[⇧ Table of Contents](#docs)
|
253
|
+
|
254
|
+
|
255
|
+
### ↳ Mark a test as failed
|
256
|
+
|
257
|
+
When you need a custom failure message use `fail` method:
|
258
|
+
|
259
|
+
```ruby
|
260
|
+
# will generate standard failure message
|
261
|
+
assert(1) == 2
|
262
|
+
|
263
|
+
# using custom failure message
|
264
|
+
1 == 2 || fail('expected 1 to be equal to 2 :(')
|
265
|
+
```
|
266
|
+
|
267
|
+
Assertions that comes after a failure will be ignored.
|
268
|
+
|
269
|
+
If you need all assertions to be evaluated regardless failures use `continue_on_failures(true)` at spec level(not inside test).
|
270
|
+
|
271
|
+
|
272
|
+
[⇧ Table of Contents](#docs)
|
273
|
+
|
274
|
+
|
275
|
+
## Shared examples and setups
|
276
|
+
|
277
|
+
Often you need to share some setups and tests(a.k.a examples) between various specs.
|
278
|
+
|
279
|
+
To define shared setups/examples simply define a module that includes `Minispec`.
|
280
|
+
|
281
|
+
Later that module can be included into any spec.
|
282
|
+
|
283
|
+
```ruby
|
284
|
+
module MailboxAssets
|
285
|
+
include Minispec
|
286
|
+
|
287
|
+
before { @mailbox = Mailbox.new }
|
288
|
+
|
289
|
+
test '#deliver' do
|
290
|
+
# ...
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
describe :SMTP do
|
295
|
+
include MailboxAssets
|
296
|
+
|
297
|
+
before do
|
298
|
+
# will run included hooks before ones defined here,
|
299
|
+
# so @mailbox is available here
|
300
|
+
@mailbox.transport = :smtp
|
301
|
+
end
|
302
|
+
|
303
|
+
# will set @mailbox's transport to :smtp and run #deliver test
|
304
|
+
end
|
305
|
+
|
306
|
+
describe :sendmail do
|
307
|
+
include MailboxAssets
|
308
|
+
|
309
|
+
before { @mailbox.transport = :sendmail }
|
310
|
+
# will set @mailbox's transport to :sendmail and run #deliver test
|
311
|
+
end
|
312
|
+
```
|
313
|
+
|
314
|
+
|
315
|
+
[⇧ Table of Contents](#docs)
|
316
|
+
|
317
|
+
|
318
|
+
### ↳ Resetting included resources
|
319
|
+
|
320
|
+
Minispec will include following resources from base module:
|
321
|
+
|
322
|
+
* `:tests`
|
323
|
+
* `:helpers`
|
324
|
+
* `:before`
|
325
|
+
* `:after`
|
326
|
+
* `:around`
|
327
|
+
* `:vars`
|
328
|
+
* `:continue_on_failures`
|
329
|
+
|
330
|
+
If you need to reset any of included resource, use `reset` method with resources to reset:
|
331
|
+
|
332
|
+
```ruby
|
333
|
+
module CPUExamples do
|
334
|
+
# some setups and tests
|
335
|
+
end
|
336
|
+
|
337
|
+
describe :MacBook do
|
338
|
+
include CPUExamples
|
339
|
+
|
340
|
+
reset :before # resets :before hooks
|
341
|
+
reset :before, :after # resets :before and :after hooks
|
342
|
+
# etc
|
343
|
+
|
344
|
+
end
|
345
|
+
```
|
346
|
+
|
347
|
+
|
348
|
+
[⇧ Table of Contents](#docs)
|
349
|
+
|
350
|
+
|
351
|
+
## Local variables and subject
|
352
|
+
|
353
|
+
Minispec provides `let` method as a clean way to define local variables. Its block are executed only once per test, when given variable used for first time.
|
354
|
+
|
355
|
+
```ruby
|
356
|
+
describe Array do
|
357
|
+
let(:array) { Array.new }
|
358
|
+
|
359
|
+
it 'is a Enumerable' do
|
360
|
+
assert(array).is_a? Enumerable
|
361
|
+
end
|
362
|
+
end
|
363
|
+
```
|
364
|
+
|
365
|
+
`subject` allow to test some object without repeatedly typing it. It is automatically set when a spec defined using Minispec's DSL:
|
366
|
+
|
367
|
+
```ruby
|
368
|
+
describe Hash do
|
369
|
+
it 'responds to :[]' do
|
370
|
+
assert.respond_to? :[]
|
371
|
+
end
|
372
|
+
end
|
373
|
+
```
|
374
|
+
|
375
|
+
In example above the subject are automatically set to `Hash` and automatically picked up by `assert`.
|
376
|
+
|
377
|
+
It can also be written as `assert(subject).respond_to? :[]` or even `assert(Hash).respond_to? :[]`, in case you prefer more explicit assertions.
|
378
|
+
|
379
|
+
[⇧ Table of Contents](#docs)
|
380
|
+
|
381
|
+
|
382
|
+
## Custom error messages
|
383
|
+
|
384
|
+
Minispec will do its best to provide detailed failure messages.
|
385
|
+
|
386
|
+
However there are cases when you need to use custom messages.
|
387
|
+
|
388
|
+
This is easily done by providing your error message as second argument,
|
389
|
+
using `:on_error` key:
|
390
|
+
|
391
|
+
```ruby
|
392
|
+
assert(pizza, on_error: "Seems not enough olives...").is_tasty
|
393
|
+
```
|
394
|
+
|
395
|
+
Now if pizza is not tasty enough, Minispec will inform us about the lack of olives rather than just generally complain about poor taste.
|
396
|
+
|
397
|
+
|
398
|
+
[⇧ Table of Contents](#docs)
|
399
|
+
|
400
|
+
|
401
|
+
## Hooks
|
402
|
+
|
403
|
+
### ↳ `before` and `before_all`
|
404
|
+
|
405
|
+
`before` callback runs before each test:
|
406
|
+
|
407
|
+
```ruby
|
408
|
+
describe Array do
|
409
|
+
before { @array = subject.new }
|
410
|
+
# @array will be different for each test
|
411
|
+
end
|
412
|
+
```
|
413
|
+
|
414
|
+
**Important:** `before` callbacks are incremental, meant that all callbacks, inherited and defined, will be called.
|
415
|
+
|
416
|
+
First will be called inherited callbacks. Defined ones will run second:
|
417
|
+
|
418
|
+
```ruby
|
419
|
+
describe :A do
|
420
|
+
before { @letter = 'A' }
|
421
|
+
|
422
|
+
context :a do
|
423
|
+
before { @letter.downcase! }
|
424
|
+
# two callbacks will run here:
|
425
|
+
# 1. @letter = 'A'
|
426
|
+
# 2. @letter.downcase!
|
427
|
+
end
|
428
|
+
|
429
|
+
# @letter is still 'A' cause child specs does not change parent's state
|
430
|
+
end
|
431
|
+
```
|
432
|
+
|
433
|
+
|
434
|
+
**`before_all`** will run only once, at spec initialization, before any test run:
|
435
|
+
|
436
|
+
```ruby
|
437
|
+
describe Array do
|
438
|
+
before_all { @array = subject.new }
|
439
|
+
# @array will be the same for all tests
|
440
|
+
end
|
441
|
+
```
|
442
|
+
|
443
|
+
**Important:** Unlike `before` callbacks, `before_all` ones **are not incremental**, so only the last defined/inherited callback will be called.
|
444
|
+
|
445
|
+
### ↳ `after` and `after_all`
|
446
|
+
|
447
|
+
`after` will run after each test, regardless was it passed or failed.
|
448
|
+
|
449
|
+
**Important:** Just like `before` callbacks, `after` ones are incremental, so all callbacks, inherited and defined, will run in appropriate order - first inherited then defined.
|
450
|
+
|
451
|
+
**`after_all`** will run only once, after all tests finished. It will run regardless tests status.
|
452
|
+
|
453
|
+
**Important:** Unlike `after` callbacks, `after_all` ones **are not incremental**, so only the last defined/inherited callback will be called.
|
454
|
+
|
455
|
+
### ↳ `around` and `around_all`
|
456
|
+
|
457
|
+
Allow to run tests inside a predefined wrapper.
|
458
|
+
|
459
|
+
The block will receive the test as first argument and should call `#run` on it:
|
460
|
+
|
461
|
+
```ruby
|
462
|
+
describe ActorSystem do
|
463
|
+
around do |test|
|
464
|
+
Celluloid::ActorSystem.new.within do
|
465
|
+
test.run
|
466
|
+
end
|
467
|
+
end
|
468
|
+
# each test will run within own ActorSystem
|
469
|
+
end
|
470
|
+
```
|
471
|
+
|
472
|
+
**Important:** Unlike `before`/`after` callbacks, `around` are not incremental, meant that only the last callback will be called regardless how many callbacks was inherited/defined.
|
473
|
+
|
474
|
+
`around_all` is similar to `around` except it will run all tests inside given block.
|
475
|
+
|
476
|
+
It will receive the spec as first argument and should call `run` on it:
|
477
|
+
|
478
|
+
```ruby
|
479
|
+
require 'tmpdir'
|
480
|
+
|
481
|
+
describe :FileManager do
|
482
|
+
around_all do |spec|
|
483
|
+
# running all tests into a temporary folder
|
484
|
+
Dir.mktmpdir do
|
485
|
+
spec.run
|
486
|
+
end
|
487
|
+
end
|
488
|
+
end
|
489
|
+
```
|
490
|
+
|
491
|
+
|
492
|
+
[⇧ Table of Contents](#docs)
|
493
|
+
|
494
|
+
### ↳ Filters
|
495
|
+
|
496
|
+
When you need a callback to run only before/after/around specific test(s), pass that tests names as arguments.
|
497
|
+
|
498
|
+
*Run only before `:a` and `:b` tests*:
|
499
|
+
|
500
|
+
```ruby
|
501
|
+
before :a, :b do
|
502
|
+
# ...
|
503
|
+
end
|
504
|
+
```
|
505
|
+
|
506
|
+
It is also possible to use `:except` option.
|
507
|
+
|
508
|
+
*Run after all except `:x`*:
|
509
|
+
|
510
|
+
```ruby
|
511
|
+
after except: :x do
|
512
|
+
# ...
|
513
|
+
end
|
514
|
+
```
|
515
|
+
|
516
|
+
And to make matchers even more useful, test names can be provided as regular expressions.
|
517
|
+
|
518
|
+
*Run around tests that match `/a/`*:
|
519
|
+
|
520
|
+
```ruby
|
521
|
+
around /a/ do
|
522
|
+
# ...
|
523
|
+
end
|
524
|
+
```
|
525
|
+
|
526
|
+
*Run before tests that match `/a/` but not before `:abc`*:
|
527
|
+
|
528
|
+
```ruby
|
529
|
+
before /a/, except: :abc do
|
530
|
+
# ...
|
531
|
+
end
|
532
|
+
```
|
533
|
+
|
534
|
+
|
535
|
+
*Run before tests that match `/a/` but not before ones that match `/ab/`*:
|
536
|
+
|
537
|
+
```ruby
|
538
|
+
before /a/, except: /ab/ do
|
539
|
+
# ...
|
540
|
+
end
|
541
|
+
```
|
542
|
+
|
543
|
+
|
544
|
+
|
545
|
+
[⇧ Table of Contents](#docs)
|
546
|
+
|
547
|
+
|
548
|
+
## Assertions
|
549
|
+
|
550
|
+
Minispec's assertions mechanism is pretty simple: tested objects are wrapped into a proxy that intercepts messages, sending them to tested object and mark assertion as passed or failed based on returned value.
|
551
|
+
|
552
|
+
There are plenty of wrappers used in Minispec. `assert` and `expect` are only few of them:
|
553
|
+
|
554
|
+
```ruby
|
555
|
+
assert(a) == b
|
556
|
+
expect(a).include?(b)
|
557
|
+
assert(a).nil?
|
558
|
+
# etc.
|
559
|
+
```
|
560
|
+
|
561
|
+
Though these assertions looks mostly ok, they are not truly semantic.<br>
|
562
|
+
Let's use some more wrappers:
|
563
|
+
|
564
|
+
```ruby
|
565
|
+
is(a) == b
|
566
|
+
does(a).include?(b)
|
567
|
+
is(a).nil?
|
568
|
+
# etc.
|
569
|
+
```
|
570
|
+
|
571
|
+
Here is the list of available wrappers:
|
572
|
+
|
573
|
+
* `assert`
|
574
|
+
* `affirm`
|
575
|
+
* `assume`
|
576
|
+
* `assure`
|
577
|
+
* `expect`
|
578
|
+
* `verify`
|
579
|
+
* `check`
|
580
|
+
* `prove`
|
581
|
+
* `would`
|
582
|
+
* `will`
|
583
|
+
* `is`
|
584
|
+
* `is?`
|
585
|
+
* `are`
|
586
|
+
* `are?`
|
587
|
+
* `was`
|
588
|
+
* `was?`
|
589
|
+
* `does`
|
590
|
+
* `does?`
|
591
|
+
* `did`
|
592
|
+
* `did?`
|
593
|
+
* `have`
|
594
|
+
* `have?`
|
595
|
+
* `has`
|
596
|
+
* `has?`
|
597
|
+
|
598
|
+
[⇧ Table of Contents](#docs)
|
599
|
+
|
600
|
+
|
601
|
+
### ↳ Negative assertions
|
602
|
+
|
603
|
+
There are two kind of negations in Minispec:
|
604
|
+
|
605
|
+
* negative wrappers
|
606
|
+
* post-wrapper negations
|
607
|
+
|
608
|
+
List of negative wrappers:
|
609
|
+
|
610
|
+
* `refute`
|
611
|
+
* `negate`
|
612
|
+
* `fail_if`
|
613
|
+
* `not_expected`
|
614
|
+
* `assert_not`
|
615
|
+
|
616
|
+
```ruby
|
617
|
+
refute(a) == b
|
618
|
+
fail_if(a).include?(b)
|
619
|
+
# etc.
|
620
|
+
```
|
621
|
+
|
622
|
+
List of post-wrapper negations:
|
623
|
+
|
624
|
+
* `not`
|
625
|
+
* `has_not`
|
626
|
+
* `have_not`
|
627
|
+
* `does_not`
|
628
|
+
* `did_not`
|
629
|
+
* `is_not`
|
630
|
+
* `is_not_a`
|
631
|
+
* `wont`
|
632
|
+
|
633
|
+
```ruby
|
634
|
+
assert(a).not == b
|
635
|
+
assert(a).does_not.include?(b)
|
636
|
+
assert(a).is_not.nil?
|
637
|
+
# etc.
|
638
|
+
```
|
639
|
+
|
640
|
+
[⇧ Table of Contents](#docs)
|
641
|
+
|
642
|
+
|
643
|
+
### ↳ Semantic sugar
|
644
|
+
|
645
|
+
Just like post-wrapper negations, sugar methods are used after a wrapper and are aimed to add some more semantic sense to assertions.
|
646
|
+
|
647
|
+
List of semantic sugar methods:
|
648
|
+
|
649
|
+
* `a`
|
650
|
+
* `is`
|
651
|
+
* `is_a`
|
652
|
+
* `are`
|
653
|
+
* `will`
|
654
|
+
* `was`
|
655
|
+
* `does`
|
656
|
+
* `did`
|
657
|
+
* `have`
|
658
|
+
* `has`
|
659
|
+
* `to`
|
660
|
+
* `be`
|
661
|
+
* `been`
|
662
|
+
|
663
|
+
```ruby
|
664
|
+
is(x).a.instance_of?(Y)
|
665
|
+
assert(a).is.nil?
|
666
|
+
expect(x).was.called?
|
667
|
+
assert(x).has.been.locked?
|
668
|
+
expect(a).to.include?(b)
|
669
|
+
expect(a).to.be.empty?
|
670
|
+
expect(x).to.have.children
|
671
|
+
# etc.
|
672
|
+
```
|
673
|
+
|
674
|
+
[⇧ Table of Contents](#docs)
|
675
|
+
|
676
|
+
|
677
|
+
## Helpers
|
678
|
+
|
679
|
+
In most cases native Ruby methods are enough for some basic testing.<br>
|
680
|
+
However some basic testing is never enough for code that matters.
|
681
|
+
|
682
|
+
Minispec's helpers system allows to write tests of any complexity without sacrifice simplicity and semantic readability.
|
683
|
+
|
684
|
+
The idea is simple: if the wrapper detects a helper with same name as received message, it will will pass that message to the helper rather than to the tested object.
|
685
|
+
|
686
|
+
Helper is receiving tested object as first argument and can apply any assertions on it.
|
687
|
+
|
688
|
+
It does not mater what a helper returns. If some assertion fails inside a helper, the test that calls the helper will be marked as failed and failure will contain both test and helper's locations.
|
689
|
+
|
690
|
+
*`blank?` helper not defined, so `blank?` message are passed to `a`. If `a` does not respond to `blank?`, a `NoMethodError` will be raised*:
|
691
|
+
|
692
|
+
```ruby
|
693
|
+
is(a).blank?
|
694
|
+
```
|
695
|
+
|
696
|
+
*`blank?` helper defined, so `blank?` message are passed to helper rather than to `a`. `a` may or may not respond to `blank?`*:
|
697
|
+
|
698
|
+
```ruby
|
699
|
+
# defining a helper
|
700
|
+
helper :blank? do |a|
|
701
|
+
# validating given object
|
702
|
+
is(a.to_s).empty?
|
703
|
+
end
|
704
|
+
|
705
|
+
# defining a test
|
706
|
+
should 'return a non-empty string' do
|
707
|
+
a = Some.abstract.string
|
708
|
+
is(a).blank?
|
709
|
+
end
|
710
|
+
```
|
711
|
+
|
712
|
+
[⇧ Table of Contents](#docs)
|
713
|
+
|
714
|
+
### ↳ Built-in helpers
|
715
|
+
|
716
|
+
Minispec comes with some built-in helpers for most common scenarios: raised exceptions, thrown symbols, booleans etc.
|
717
|
+
|
718
|
+
#### ↳ `raise` helper
|
719
|
+
|
720
|
+
|
721
|
+
*Without arguments any exception will be accepted*:
|
722
|
+
|
723
|
+
```ruby
|
724
|
+
does { some risky code }.raise
|
725
|
+
|
726
|
+
# can also be written as
|
727
|
+
does { some risky code }.raise?
|
728
|
+
does { some risky code }.raise_error?
|
729
|
+
expect { some risky code }.to_raise
|
730
|
+
expect { some risky code }.to_raise_error
|
731
|
+
```
|
732
|
+
|
733
|
+
*When given a class it will accept only exceptions of given class*:
|
734
|
+
|
735
|
+
```ruby
|
736
|
+
expect { some risky code }.to_raise NoMethodError
|
737
|
+
```
|
738
|
+
|
739
|
+
*When given a string only exceptions with same message will be accepted*:
|
740
|
+
|
741
|
+
```ruby
|
742
|
+
expect { some risky code }.to_raise 'some error message'
|
743
|
+
```
|
744
|
+
|
745
|
+
*When given a Regexp only exceptions with same message as given string will be accepted*:
|
746
|
+
|
747
|
+
```ruby
|
748
|
+
expect { some risky code }.to_raise /some error message/
|
749
|
+
```
|
750
|
+
|
751
|
+
*When both class and String/Regexp given, it will accept only exceptions of given class that equals/match given String/Regexp*:
|
752
|
+
|
753
|
+
```ruby
|
754
|
+
expect { some risky code }.to_raise NoMethodError, 'some error message'
|
755
|
+
expect { some risky code }.to_raise NoMethodError, /some error message/
|
756
|
+
```
|
757
|
+
|
758
|
+
**When you need even more control over raised exception, use a block.**
|
759
|
+
|
760
|
+
*Expect any error to be raised except LoadError:*
|
761
|
+
|
762
|
+
```ruby
|
763
|
+
expect { something }.to_raise {|e| e.is_a?(Exception) && e.class != LoadError}
|
764
|
+
```
|
765
|
+
|
766
|
+
*Expect raised error backtrace to contain a specific line:*
|
767
|
+
|
768
|
+
```ruby
|
769
|
+
expect { something }.to_raise {|e| e.backtrace.find {|l| l =~ /something/} }
|
770
|
+
```
|
771
|
+
|
772
|
+
[⇧ Table of Contents](#docs)
|
773
|
+
|
774
|
+
#### ↳ `throw` helper
|
775
|
+
|
776
|
+
*When called without arguments any thrown symbol accepted*:
|
777
|
+
|
778
|
+
```ruby
|
779
|
+
does { some code }.throw
|
780
|
+
|
781
|
+
# can also be written as
|
782
|
+
does { some code }.throw?
|
783
|
+
does { some code }.throw_symbol?
|
784
|
+
expect { some code }.to_throw
|
785
|
+
expect { some code }.to_throw_symbol
|
786
|
+
```
|
787
|
+
|
788
|
+
*When called with a symbol it will pass only if given symbol thrown*:
|
789
|
+
|
790
|
+
```ruby
|
791
|
+
expect { some code }.to_throw :some_symbol
|
792
|
+
```
|
793
|
+
|
794
|
+
*When called with a symbol and a value it will pass only if given symbol thrown with given value*:
|
795
|
+
|
796
|
+
```ruby
|
797
|
+
expect { some code }.to_throw :some_symbol, 'some value'
|
798
|
+
```
|
799
|
+
|
800
|
+
**Also a block can be used to validate thrown symbol.**<br>
|
801
|
+
**Important:** when a block used, only thrown symbol passed to block, so no way to validate the value by block.
|
802
|
+
|
803
|
+
*Expect any symbol to be thrown except `:halt`*
|
804
|
+
|
805
|
+
```ruby
|
806
|
+
does { some code }.throw? {|s| s != :halt}
|
807
|
+
```
|
808
|
+
|
809
|
+
**Limitations:** the code to be inspected for thrown symbols should run out of its `catch` block.
|
810
|
+
|
811
|
+
*This test wont pass cause thrown symbol are caught early:*
|
812
|
+
|
813
|
+
```ruby
|
814
|
+
describe User do
|
815
|
+
|
816
|
+
def create_account *args
|
817
|
+
catch :invalid_email do
|
818
|
+
User.new *args
|
819
|
+
end
|
820
|
+
end
|
821
|
+
|
822
|
+
it 'fails if invalid email given' do
|
823
|
+
expect { create_account(email: 'blah') }.to_throw :invalid_email
|
824
|
+
end
|
825
|
+
end
|
826
|
+
```
|
827
|
+
|
828
|
+
For this to work you should run `User.new` outside `catch` block.
|
829
|
+
|
830
|
+
[⇧ Table of Contents](#docs)
|
831
|
+
|
832
|
+
|
833
|
+
#### ↳ Boolean helpers
|
834
|
+
|
835
|
+
*`true?`: expects tested object to be `true`*:
|
836
|
+
|
837
|
+
```ruby
|
838
|
+
is(a).true?
|
839
|
+
assert(a).is.true?
|
840
|
+
|
841
|
+
# same as
|
842
|
+
assert(a) == true
|
843
|
+
```
|
844
|
+
|
845
|
+
*`false?`: expects tested object to be `false`*:
|
846
|
+
|
847
|
+
```ruby
|
848
|
+
is(a).false?
|
849
|
+
assert(a).is.false?
|
850
|
+
|
851
|
+
# same as
|
852
|
+
assert(a) == false
|
853
|
+
```
|
854
|
+
|
855
|
+
*`positive`, `positive?`, `truthful?, `non_falsy?`: expects tested object to not be `nil` nor `false`*:
|
856
|
+
|
857
|
+
```ruby
|
858
|
+
is(a).positive?
|
859
|
+
is(a).truthful?
|
860
|
+
expect(a).is.positive
|
861
|
+
expect(a).is.non_falsy?
|
862
|
+
```
|
863
|
+
|
864
|
+
|
865
|
+
[⇧ Table of Contents](#docs)
|
866
|
+
|
867
|
+
#### ↳ `silent` helper
|
868
|
+
|
869
|
+
`silent` (aliased as `silent?` and `is_silent`) expects given block to output nothing, that's it, the block should write nothing to STDOUT nor to STDERR.
|
870
|
+
|
871
|
+
```ruby
|
872
|
+
is { some_code_here }.silent?
|
873
|
+
```
|
874
|
+
|
875
|
+
or
|
876
|
+
|
877
|
+
```ruby
|
878
|
+
assert do
|
879
|
+
some
|
880
|
+
more
|
881
|
+
code
|
882
|
+
here
|
883
|
+
end.is_silent
|
884
|
+
```
|
885
|
+
|
886
|
+
|
887
|
+
[⇧ Table of Contents](#docs)
|
888
|
+
|
889
|
+
|
890
|
+
#### ↳ `Array` helpers
|
891
|
+
|
892
|
+
*`same_elements`: expects tested object is an array that have same elements as given array*:
|
893
|
+
|
894
|
+
```ruby
|
895
|
+
a = [1, 2, :x]
|
896
|
+
b = [:x, 1, 2]
|
897
|
+
expect(a).has.same_elements_as(b)
|
898
|
+
# => passed
|
899
|
+
```
|
900
|
+
|
901
|
+
*`contain`: expects tested object is an array that contains given elements. Order does not matter*:
|
902
|
+
|
903
|
+
```ruby
|
904
|
+
a = [1, 2, :x]
|
905
|
+
does(a).contain? :x, 2
|
906
|
+
# => passed
|
907
|
+
does(a).contain? :y, 2
|
908
|
+
# => failed
|
909
|
+
```
|
910
|
+
|
911
|
+
[⇧ Table of Contents](#docs)
|
912
|
+
|
913
|
+
|
914
|
+
### ↳ Custom helpers
|
915
|
+
|
916
|
+
The power of Minispec's helpers are revealed in full only when you define your own helpers. It is simply done by using `helper` method with a block. The block will receive tested object as first argument and you can test it to the backbone:
|
917
|
+
|
918
|
+
```ruby
|
919
|
+
describe Cooking do
|
920
|
+
helper :looks_like_a_pizza? do |food|
|
921
|
+
assert(food).contains? :olives, :cheese
|
922
|
+
end
|
923
|
+
|
924
|
+
it 'cooks a pizza' do
|
925
|
+
food = Cook.new.pizza
|
926
|
+
does(food).looks_like_a_pizza?
|
927
|
+
end
|
928
|
+
end
|
929
|
+
```
|
930
|
+
|
931
|
+
When you pass some arguments into helper they comes after tested object:
|
932
|
+
|
933
|
+
```ruby
|
934
|
+
helper :ok_with_body? do |response, body|
|
935
|
+
assert(response.status) == 200
|
936
|
+
assert(response.body) == body
|
937
|
+
end
|
938
|
+
|
939
|
+
test 'index action' do
|
940
|
+
get '/'
|
941
|
+
is(last_response).ok_with_body? 'index'
|
942
|
+
end
|
943
|
+
```
|
944
|
+
|
945
|
+
[⇧ Table of Contents](#docs)
|
946
|
+
|
947
|
+
|
948
|
+
### ↳ Helpers with blocks
|
949
|
+
|
950
|
+
If object passed within a block, the helper will receive that block as first argument.
|
951
|
+
|
952
|
+
Please note that the block will be received as usual argument rather than a block.
|
953
|
+
|
954
|
+
```ruby
|
955
|
+
helper :blank? do |block|
|
956
|
+
is(block.call).empty?
|
957
|
+
# or is(&block).empty?
|
958
|
+
end
|
959
|
+
|
960
|
+
should 'pass' do
|
961
|
+
is { '' }.blank?
|
962
|
+
end
|
963
|
+
```
|
964
|
+
|
965
|
+
When a helper used with a block, the block will be passed as last argument,
|
966
|
+
in form of a simple argument rather than a block:
|
967
|
+
|
968
|
+
```ruby
|
969
|
+
helper :any_of? do |arr, block|
|
970
|
+
assert(arr).any?(&block)
|
971
|
+
end
|
972
|
+
|
973
|
+
should 'pass' do
|
974
|
+
has([1, 2]).any_of? {|v| v > 1}
|
975
|
+
end
|
976
|
+
```
|
977
|
+
|
978
|
+
[⇧ Table of Contents](#docs)
|
979
|
+
|
980
|
+
|
981
|
+
### ↳ Helpers aliases
|
982
|
+
|
983
|
+
Often you need some helper to be accessed by various names.<br>
|
984
|
+
Minispec allows to create helper aliases by using `alias_helper` method.<br>
|
985
|
+
Simply pass new name as first argument and existing helper name as second:
|
986
|
+
|
987
|
+
```ruby
|
988
|
+
helper :open? do |door|
|
989
|
+
# ...
|
990
|
+
end
|
991
|
+
alias_helper :not_closed, :open?
|
992
|
+
|
993
|
+
it 'creates a open door' do
|
994
|
+
door = Door.new(open: true)
|
995
|
+
is(door).open?
|
996
|
+
end
|
997
|
+
|
998
|
+
it 'opens door with open!' do
|
999
|
+
door = Door.new
|
1000
|
+
door.open!
|
1001
|
+
assert(door).not_closed
|
1002
|
+
end
|
1003
|
+
```
|
1004
|
+
|
1005
|
+
|
1006
|
+
[⇧ Table of Contents](#docs)
|
1007
|
+
|
1008
|
+
|
1009
|
+
## Mocking
|
1010
|
+
|
1011
|
+
Minispec comes with a pretty full set of mocking instruments.
|
1012
|
+
|
1013
|
+
Though there are obvious differences, these instruments are kind of similar to ones used in another libraries like [mocha](https://github.com/freerange/mocha), [rr](https://github.com/rr/rr) and [rspec-mocks](https://github.com/rspec/rspec-mocks).
|
1014
|
+
|
1015
|
+
Perhaps sometimes verbose, they gives you full control over mocked objects.
|
1016
|
+
|
1017
|
+
|
1018
|
+
### ↳ Expectations
|
1019
|
+
|
1020
|
+
Useful when you expect some object to receive some message(s).
|
1021
|
+
|
1022
|
+
Expectations are validated after current test evaluation finished. So the object are expected to receive given message(s) somewhere in the near future, just before current test ends.
|
1023
|
+
|
1024
|
+
Use `to_receive` helper to add an expectation.
|
1025
|
+
|
1026
|
+
*Expect bob to eat an apple:*
|
1027
|
+
|
1028
|
+
```ruby
|
1029
|
+
apple = Apple.new
|
1030
|
+
bob = Kid.new
|
1031
|
+
bob.bag << apple
|
1032
|
+
expect(apple).to_receive(:eaten)
|
1033
|
+
```
|
1034
|
+
|
1035
|
+
[⇧ Table of Contents](#docs)
|
1036
|
+
|
1037
|
+
|
1038
|
+
**↳ Expecting multiple messages**
|
1039
|
+
|
1040
|
+
Often you need to expect multiple messages on a object.
|
1041
|
+
|
1042
|
+
You could of course add a expectation for each message:
|
1043
|
+
|
1044
|
+
```ruby
|
1045
|
+
expect(a).to_receive :x
|
1046
|
+
expect(a).to_receive :y
|
1047
|
+
```
|
1048
|
+
|
1049
|
+
but this is tedious and becomes hairy very quickly.
|
1050
|
+
|
1051
|
+
Recommended approach is to use `:to_receive` helper with multiple arguments:
|
1052
|
+
|
1053
|
+
```ruby
|
1054
|
+
expect(a).to_receive(:x, :y)
|
1055
|
+
```
|
1056
|
+
|
1057
|
+
Much better, huh?
|
1058
|
+
|
1059
|
+
**↳ Assert given message(s) never received**
|
1060
|
+
|
1061
|
+
*Ensure `a` wont receive `:b` message:*
|
1062
|
+
|
1063
|
+
```ruby
|
1064
|
+
expect(a).to_not.receive(:b)
|
1065
|
+
```
|
1066
|
+
|
1067
|
+
*same:*
|
1068
|
+
|
1069
|
+
```ruby
|
1070
|
+
refute(a).receive(:b)
|
1071
|
+
```
|
1072
|
+
|
1073
|
+
*Ensure `a` wont receive `:x` message nor `:y`:*
|
1074
|
+
|
1075
|
+
```ruby
|
1076
|
+
assert(a).wont.receive(:x, :y)
|
1077
|
+
```
|
1078
|
+
|
1079
|
+
if at least one of messages received, the test will fail.
|
1080
|
+
|
1081
|
+
[⇧ Table of Contents](#docs)
|
1082
|
+
|
1083
|
+
|
1084
|
+
### ↳ Constraints
|
1085
|
+
|
1086
|
+
Sometimes just checking that some messages are received is not enough. We need to know whether certain message received with certain arguments and returned/raised/thrown certain value.
|
1087
|
+
|
1088
|
+
Minispec allows to add such kind of constraints with ease.
|
1089
|
+
|
1090
|
+
|
1091
|
+
#### ↳ Arguments
|
1092
|
+
|
1093
|
+
*Expect `a` to receive `:b` message with x, y arguments:*
|
1094
|
+
|
1095
|
+
```ruby
|
1096
|
+
expect(a).to_receive(:b).with('x', 'y')
|
1097
|
+
```
|
1098
|
+
|
1099
|
+
*Expect `a` to receive `:b` message with whatever arguments:*
|
1100
|
+
|
1101
|
+
```ruby
|
1102
|
+
expect(a).to_receive(:b).with {|*| true}
|
1103
|
+
```
|
1104
|
+
|
1105
|
+
*Expect `a` to receive `:b` message with exactly 2 arguments, whatever they are:*
|
1106
|
+
|
1107
|
+
```ruby
|
1108
|
+
expect(a).to_receive(:b).with {|*a| a.size == 2}
|
1109
|
+
```
|
1110
|
+
|
1111
|
+
*Expect at least 2 arguments and second one to be bigger than first:*
|
1112
|
+
|
1113
|
+
```ruby
|
1114
|
+
expect(a).to_receive(:b).with {|x,y| y > x}
|
1115
|
+
```
|
1116
|
+
|
1117
|
+
*Expect exactly 2 arguments and second one to be bigger than first:*
|
1118
|
+
|
1119
|
+
```ruby
|
1120
|
+
expect(a).to_receive(:b).with do |*a|
|
1121
|
+
assert(a.size) == 2
|
1122
|
+
is(a.last) > a.first
|
1123
|
+
end
|
1124
|
+
```
|
1125
|
+
|
1126
|
+
Another way is to just return `true` or `false`. If block returns true, the test will pass.
|
1127
|
+
|
1128
|
+
```ruby
|
1129
|
+
expect(a).to_receive(:b).with {|*a| a.size == 2 && a.last > a.first}
|
1130
|
+
```
|
1131
|
+
|
1132
|
+
|
1133
|
+
**↳ Arguments on multiple expectations**
|
1134
|
+
|
1135
|
+
*Expect `a` to receive `:x` and `:y` messages with 1 and 2 arguments respectively:*
|
1136
|
+
|
1137
|
+
```ruby
|
1138
|
+
expect(a).to_receive(:x, :y).with(1, 2)
|
1139
|
+
```
|
1140
|
+
|
1141
|
+
for this test to pass, both `a.x(1)` and `a.y(2)` should be called.
|
1142
|
+
|
1143
|
+
You can also use a block to validate arguments.
|
1144
|
+
|
1145
|
+
*Expect `a` to receive `:x` and `:y` messages where x's argument is 1 and y's argument is bigger than 2:*
|
1146
|
+
|
1147
|
+
```ruby
|
1148
|
+
expect(a).to_receive(:x, :y).with do |x,y|
|
1149
|
+
is(x) == 1
|
1150
|
+
is(y) > 2
|
1151
|
+
end
|
1152
|
+
```
|
1153
|
+
|
1154
|
+
Another way is to just return `true` or `false`. If block returns true, the test will pass.
|
1155
|
+
|
1156
|
+
```ruby
|
1157
|
+
expect(a).to_receive(:x, :y).with {|x,y| x == 1 && y > 2}
|
1158
|
+
```
|
1159
|
+
|
1160
|
+
[⇧ Table of Contents](#docs)
|
1161
|
+
|
1162
|
+
|
1163
|
+
#### ↳ Returned value
|
1164
|
+
|
1165
|
+
*Expect `a` to receive `:b` message and return 'x':*
|
1166
|
+
|
1167
|
+
```ruby
|
1168
|
+
expect(a).to_receive(:b).and_return('x')
|
1169
|
+
```
|
1170
|
+
|
1171
|
+
*Expect `a` to receive `:b` message and return a value bigger than 10:*
|
1172
|
+
|
1173
|
+
```ruby
|
1174
|
+
expect(a).to_receive(:b).and_return {|returned_value| is(returned_value) > 10}
|
1175
|
+
```
|
1176
|
+
|
1177
|
+
Another way is to just return `true` or `false`. If block returns true, the test will pass.
|
1178
|
+
|
1179
|
+
```ruby
|
1180
|
+
expect(a).to_receive(:b).and_return {|returned_value| returned_value > 10}
|
1181
|
+
```
|
1182
|
+
|
1183
|
+
|
1184
|
+
**↳ Returned value on multiple expectations**
|
1185
|
+
|
1186
|
+
*Expect `a` to receive `:x` and `:y` messages and return 1 and 2 respectively:*
|
1187
|
+
|
1188
|
+
```ruby
|
1189
|
+
expect(a).to_receive(:x, :y).and_return(1, 2)
|
1190
|
+
```
|
1191
|
+
|
1192
|
+
for this test to pass, `a.x` should return 1 and `a.y` should return 2.
|
1193
|
+
|
1194
|
+
If all messages expected to return same value, use a single argument.
|
1195
|
+
|
1196
|
+
*Expect `a` to receive `:x` and `:y` messages and both to return 1:*
|
1197
|
+
|
1198
|
+
```ruby
|
1199
|
+
expect(a).to_receive(:x, :y).and_return(1)
|
1200
|
+
```
|
1201
|
+
|
1202
|
+
for this to pass both `:x` and `:y` should return 1.
|
1203
|
+
|
1204
|
+
When you need full control over returned values, use a block.
|
1205
|
+
|
1206
|
+
*Expect `a` to receive `:x` and `:y` messages where `:x` will return 1 and `:y` a value bigger than 5:*
|
1207
|
+
|
1208
|
+
```ruby
|
1209
|
+
expect(a).to_receive(:x, :y).and_return do |x,y|
|
1210
|
+
is(x) == 1
|
1211
|
+
is(y) > 5
|
1212
|
+
end
|
1213
|
+
```
|
1214
|
+
|
1215
|
+
Another way is to just return `true` or `false`. If block returns true, the test will pass.
|
1216
|
+
|
1217
|
+
```ruby
|
1218
|
+
expect(a).to_receive(:x, :y).and_return {|x,y| x == 1 && y > 5}
|
1219
|
+
```
|
1220
|
+
|
1221
|
+
[⇧ Table of Contents](#docs)
|
1222
|
+
|
1223
|
+
|
1224
|
+
#### ↳ Raised exception
|
1225
|
+
|
1226
|
+
When you expect a message to raise a exception, use `and_raise` expectation.
|
1227
|
+
|
1228
|
+
*Expect `a` to receive `:b` message and raise something:*
|
1229
|
+
|
1230
|
+
```ruby
|
1231
|
+
expect(a).to_receive(:b).and_raise
|
1232
|
+
```
|
1233
|
+
|
1234
|
+
When you expect a specific error, pass expected error class as first argument.
|
1235
|
+
|
1236
|
+
*Expect `a` to receive `:b` message and raise NoMethodError error:*
|
1237
|
+
|
1238
|
+
```ruby
|
1239
|
+
expect(a).to_receive(:b).and_raise NoMethodError
|
1240
|
+
```
|
1241
|
+
|
1242
|
+
|
1243
|
+
When you expect a specific error with a specific message, pass expected error class and expected message wrapped into an array.
|
1244
|
+
|
1245
|
+
*Expect `a` to receive `:b` message and raise CustomError error with 'something went wrong' message:*
|
1246
|
+
|
1247
|
+
```ruby
|
1248
|
+
expect(a).to_receive(:b).and_raise [CustomError, 'something went wrong']
|
1249
|
+
```
|
1250
|
+
|
1251
|
+
|
1252
|
+
When you need error message to match some string, use a Regexp.
|
1253
|
+
|
1254
|
+
*Expect `a` to receive `:b` message and raise CustomError error with a message that match `/something/`:*
|
1255
|
+
|
1256
|
+
```ruby
|
1257
|
+
expect(a).to_receive(:b).and_raise [CustomError, /something/]
|
1258
|
+
```
|
1259
|
+
|
1260
|
+
**When you need even more control over raised exception, use a block.**
|
1261
|
+
|
1262
|
+
*Expect `a` to receive `:b` message and raise anything but LoadError:*
|
1263
|
+
|
1264
|
+
```ruby
|
1265
|
+
expect(a).to_receive(:b).and_raise do |e|
|
1266
|
+
assert(e).is_a?(Exception)
|
1267
|
+
assert(e.class) != LoadError
|
1268
|
+
end
|
1269
|
+
```
|
1270
|
+
|
1271
|
+
Another way is to just return `true` or `false`. If block returns true, the test will pass.
|
1272
|
+
|
1273
|
+
```ruby
|
1274
|
+
expect(a).to_receive(:b).and_raise do |e|
|
1275
|
+
e.is_a?(Exception) && e.class != LoadError
|
1276
|
+
end
|
1277
|
+
```
|
1278
|
+
|
1279
|
+
|
1280
|
+
**↳ Raised exception on multiple expectations**
|
1281
|
+
|
1282
|
+
*Expect `a` to receive `:x` and `:y` messages and both to raise something:*
|
1283
|
+
|
1284
|
+
```ruby
|
1285
|
+
expect(a).to_receive(:x, :y).and_raise
|
1286
|
+
```
|
1287
|
+
|
1288
|
+
If you expect a specific error for each message to be raised, just pass expected errors as arguments.
|
1289
|
+
|
1290
|
+
*Expect `a` to receive `:x` and `:y` messages where `:x` will raise NoMethodError error and `:y` will raise StandardError:*
|
1291
|
+
|
1292
|
+
```ruby
|
1293
|
+
expect(a).to_receive(:x, :y).and_raise(NoMethodError, StandardError)
|
1294
|
+
```
|
1295
|
+
|
1296
|
+
If you need also to check error messages, pass error class and message wrapped into an array.
|
1297
|
+
|
1298
|
+
*Expect `a` to receive `:x` and `:y` messages where `:x` will raise NoMethodError that match /X/ and `:y` will raise StandardError that match /Y/:*
|
1299
|
+
|
1300
|
+
```ruby
|
1301
|
+
expect(a).to_receive(:x, :y).and_raise([NoMethodError, /X/], [StandardError, /Y/])
|
1302
|
+
```
|
1303
|
+
|
1304
|
+
It's not a sin to expect only error type on some message and error type with message on another.
|
1305
|
+
|
1306
|
+
*Expect `a` to receive `:x` and `:y` messages where `:x` will raise NoMethodError and `:y` will raise StandardError that match /Y/:*
|
1307
|
+
|
1308
|
+
```ruby
|
1309
|
+
expect(a).to_receive(:x, :y).and_raise(NoMethodError, [StandardError, /Y/])
|
1310
|
+
```
|
1311
|
+
|
1312
|
+
**If all messages are expected to raise same error, use a single argument.**
|
1313
|
+
|
1314
|
+
*Expect `a` to receive `:x` and `:y` messages and both to raise StandardError:*
|
1315
|
+
|
1316
|
+
```ruby
|
1317
|
+
expect(a).to_receive(:x, :y).and_raise(StandardError)
|
1318
|
+
```
|
1319
|
+
|
1320
|
+
**It is also possible to use a block for validating raised exceptions.**<br>
|
1321
|
+
The block will receive as many arguments as messages expected. Each argument will be a exception instance if its message raised something or `nil` otherwise.
|
1322
|
+
|
1323
|
+
*Expect `a` to receive `:x` and `:y` messages where `:x` will raise NoMethodError and `:y`'s backtrace will contain a specific line:*
|
1324
|
+
|
1325
|
+
```ruby
|
1326
|
+
expect(a).to_receive(:x, :y).and_raise do |x,y|
|
1327
|
+
assert(x).is_a? NoMethodError
|
1328
|
+
assert(y.backtrace).any? {|l| l =~ /something/}
|
1329
|
+
end
|
1330
|
+
```
|
1331
|
+
|
1332
|
+
Another way is to just return `true` or `false`. If block returns true, the test will pass.
|
1333
|
+
|
1334
|
+
```ruby
|
1335
|
+
expect(a).to_receive(:x, :y).and_raise do |x,y|
|
1336
|
+
x.is_a?(NoMethodError) && y.backtrace.any? {|l| l =~ /something/}
|
1337
|
+
end
|
1338
|
+
```
|
1339
|
+
|
1340
|
+
|
1341
|
+
**↳ Assert nothing raised**
|
1342
|
+
|
1343
|
+
Often you need to assure some message received and nothing raised. There are `without_raise` expectation that will ensure nothing raised on message receiving.
|
1344
|
+
|
1345
|
+
*Expect `a` to receive `:b` and nothing raises:*
|
1346
|
+
|
1347
|
+
```ruby
|
1348
|
+
expect(a).to_receive(:b).without_raise
|
1349
|
+
```
|
1350
|
+
|
1351
|
+
Also works on multiple expectations. In this case the test will fail if at least one message raises a exception.
|
1352
|
+
|
1353
|
+
*Expect `a` to receive `:x` and `:y` without raise anything:*
|
1354
|
+
|
1355
|
+
```ruby
|
1356
|
+
expect(a).to_receive(:x, :y).without_raise
|
1357
|
+
```
|
1358
|
+
|
1359
|
+
|
1360
|
+
[⇧ Table of Contents](#docs)
|
1361
|
+
|
1362
|
+
|
1363
|
+
#### ↳ Thrown symbol
|
1364
|
+
|
1365
|
+
When you expect a symbol to be thrown, use `and_throw` expectation.
|
1366
|
+
|
1367
|
+
*Expect `a` to receive `:b` message and throw `:x` symbol:*
|
1368
|
+
|
1369
|
+
```ruby
|
1370
|
+
expect(a).to_receive(:b).and_throw :x
|
1371
|
+
```
|
1372
|
+
|
1373
|
+
**Note:** unlike `and_raise` expectation, `and_throw` can not be used without arguments. It requires exactly one argument - the expected symbol(unless a block used).
|
1374
|
+
|
1375
|
+
Also a block can be used to validate thrown symbol. This is the case when `and_throw` expectation should be used without arguments.
|
1376
|
+
|
1377
|
+
*Expect `a` to receive `:b` message and throw any symbol except `:x`:*
|
1378
|
+
|
1379
|
+
```ruby
|
1380
|
+
expect(a).to_receive(:b).and_throw do |s|
|
1381
|
+
assert(s).is_a? Symbol # making sure something actually thrown
|
1382
|
+
assert(s) != :x
|
1383
|
+
end
|
1384
|
+
```
|
1385
|
+
|
1386
|
+
Another way is to just return `true` or `false`. If block returns true, the test will pass.
|
1387
|
+
|
1388
|
+
```ruby
|
1389
|
+
expect(a).to_receive(:b).and_throw {|s| s.is_a?(Symbol) && s != :x }
|
1390
|
+
```
|
1391
|
+
|
1392
|
+
|
1393
|
+
**Limitations:** unlike `throw?` helper, expectations can only check for thrown symbol, so there is no way to get and validate thrown value with expectations.
|
1394
|
+
|
1395
|
+
|
1396
|
+
**↳ Thrown symbol on multiple expectations**
|
1397
|
+
|
1398
|
+
When multiple messages expected, `and_throw` method will accept same number of arguments as the number of expected messages.
|
1399
|
+
|
1400
|
+
*Expect `a` to receive `:x` and `:y` messages and throw `:xs` and `:ys` symbols respectively:*
|
1401
|
+
|
1402
|
+
```ruby
|
1403
|
+
expect(a).to_receive(:x, :y).and_throw(:sx, :sy)
|
1404
|
+
```
|
1405
|
+
|
1406
|
+
If all messages are expected to raise same symbol, use a single argument.
|
1407
|
+
|
1408
|
+
*Expect `a` to receive `:x` and `:y` messages and both to throw `:halt` symbol:*
|
1409
|
+
|
1410
|
+
```ruby
|
1411
|
+
expect(a).to_receive(:x, :y).and_throw(:halt)
|
1412
|
+
```
|
1413
|
+
|
1414
|
+
When you need even more control over thrown symbols, use a block. The block will receive exactly same number of arguments as the number of expected messages. Each argument will be a symbol if its message thrown something of `nil` otherwise.
|
1415
|
+
|
1416
|
+
*Expect `a` to receive `:x` and `:y` messages where `:x` will thrown `:ok` symbol and `:y` will throw anything but `:halt` symbol:*
|
1417
|
+
|
1418
|
+
```ruby
|
1419
|
+
expect(a).to_receive(:x, :y).and_throw do |x,y|
|
1420
|
+
is(x) == :ok
|
1421
|
+
assert(y).is_a? Symbol # making sure something actually thrown
|
1422
|
+
assert(y) != :halt
|
1423
|
+
end
|
1424
|
+
```
|
1425
|
+
|
1426
|
+
Another way is to just return `true` or `false`. If block returns true, the test will pass.
|
1427
|
+
|
1428
|
+
```ruby
|
1429
|
+
expect(a).to_receive(:x, :y).and_throw do |x,y|
|
1430
|
+
x == :ok && y.is_a?(Symbol) && y != :halt
|
1431
|
+
end
|
1432
|
+
```
|
1433
|
+
|
1434
|
+
**↳ Assert nothing thrown**
|
1435
|
+
|
1436
|
+
*Expect `a` to receive `:b` message without throw any symbol:*
|
1437
|
+
|
1438
|
+
```ruby
|
1439
|
+
expect(a).to_receive(:b).without_throw
|
1440
|
+
```
|
1441
|
+
|
1442
|
+
*Expect `a` to receive `:x` and `:y` messages without throw any symbol:*
|
1443
|
+
|
1444
|
+
```ruby
|
1445
|
+
expect(a).to_receive(:x, :y).without_throw
|
1446
|
+
```
|
1447
|
+
|
1448
|
+
|
1449
|
+
[⇧ Table of Contents](#docs)
|
1450
|
+
|
1451
|
+
|
1452
|
+
#### ↳ Yielded arguments
|
1453
|
+
|
1454
|
+
`and_yield` expectation allow to check whether some block inside expected message yielded with specific arguments.
|
1455
|
+
|
1456
|
+
*Expect `a` to receive `:b` message and `:b` message to yield a block with 1, 2 arguments:*
|
1457
|
+
|
1458
|
+
```ruby
|
1459
|
+
expect(a).to_receive(:b).and_yield(1, 2)
|
1460
|
+
```
|
1461
|
+
|
1462
|
+
When you need more control, use a block.
|
1463
|
+
|
1464
|
+
*Expect `a` to receive `:b` message and `:b` message to yield a block where first argument is a string and last is a symbol:*
|
1465
|
+
|
1466
|
+
```ruby
|
1467
|
+
expect(a).to_receive(:b).and_yield do |*args|
|
1468
|
+
assert(a.first).is_a? String
|
1469
|
+
assert(a.last).is_a? Symbol
|
1470
|
+
end
|
1471
|
+
```
|
1472
|
+
|
1473
|
+
Another way is to just return `true` or `false`. If block returns true, the test will pass.
|
1474
|
+
|
1475
|
+
```ruby
|
1476
|
+
expect(a).to_receive(:b).and_yield do |*args|
|
1477
|
+
a.first.is_a?(String) && a.last.is_a?(Symbol)
|
1478
|
+
end
|
1479
|
+
```
|
1480
|
+
|
1481
|
+
|
1482
|
+
**↳ Yielded arguments on multiple expectations**
|
1483
|
+
|
1484
|
+
*Expect `a` to receive `:x` and `:y` messages where `:x` will yield a block with 1, 2 arguments and `:y` will yield a bloc with `:z` argument:*
|
1485
|
+
|
1486
|
+
```ruby
|
1487
|
+
expect(a).to_receive(:x, :y).and_yield([1, 2], :z)
|
1488
|
+
```
|
1489
|
+
|
1490
|
+
If all messages are expected to yield a block with same arguments, use a single argument on `and_yield` method.
|
1491
|
+
|
1492
|
+
|
1493
|
+
*Expect `a` to receive `:x` and `:y` messages and both `:x` to yield a block with `:z` argument:*
|
1494
|
+
|
1495
|
+
```ruby
|
1496
|
+
expect(a).to_receive(:x, :y).and_yield(:z)
|
1497
|
+
```
|
1498
|
+
|
1499
|
+
|
1500
|
+
*Expect `a` to receive `:x` and `:y` messages and both to yield a block with 1, 2 arguments:*
|
1501
|
+
|
1502
|
+
```ruby
|
1503
|
+
expect(a).to_receive(:x, :y).and_yield([1, 2])
|
1504
|
+
```
|
1505
|
+
|
1506
|
+
Please note the arguments are wrapped into an array. If using `and_yield(1, 2)` instead, the test will expect `:x` to yield 1 and `:y` to yield 2.
|
1507
|
+
|
1508
|
+
When you need full control over yielded arguments, use a block.
|
1509
|
+
|
1510
|
+
*Expect `a` to receive `:x` and `:y` messages where `:x` will yield a block with 2 or more arguments and `:y` will yield a bloc with integer only arguments:*
|
1511
|
+
|
1512
|
+
```ruby
|
1513
|
+
expect(a).to_receive(:x, :y).and_yield do |*args|
|
1514
|
+
assert(args.first.size) >= 2
|
1515
|
+
assert(args.last).all? {|a| a.is_a? Integer}
|
1516
|
+
end
|
1517
|
+
```
|
1518
|
+
|
1519
|
+
Another way is to just return `true` or `false`. If block returns true, the test will pass.
|
1520
|
+
|
1521
|
+
```ruby
|
1522
|
+
expect(a).to_receive(:x, :y).and_yield do |*args|
|
1523
|
+
args.first.size >= 2 && args.last.all? {|a| a.is_a? Integer}
|
1524
|
+
end
|
1525
|
+
```
|
1526
|
+
|
1527
|
+
|
1528
|
+
**↳ Assert nothing yielded**
|
1529
|
+
|
1530
|
+
*Expect `a` to receive `:b` message without yield any block:*
|
1531
|
+
|
1532
|
+
```ruby
|
1533
|
+
expect(a).to_receive(:b).without_yield
|
1534
|
+
```
|
1535
|
+
|
1536
|
+
*Expect `a` to receive `:x` and `:y` messages without yield any block:*
|
1537
|
+
|
1538
|
+
```ruby
|
1539
|
+
expect(a).to_receive(:x, :y).without_yield
|
1540
|
+
```
|
1541
|
+
|
1542
|
+
|
1543
|
+
[⇧ Table of Contents](#docs)
|
1544
|
+
|
1545
|
+
|
1546
|
+
#### ↳ Messages Amount
|
1547
|
+
|
1548
|
+
`count`, or its alias `times`, allow to check how many times a specific message was received.
|
1549
|
+
|
1550
|
+
*Expect `a` to receive `:b` message exactly 2 times:*
|
1551
|
+
|
1552
|
+
```ruby
|
1553
|
+
expect(a).to_receive(:b).count(2)
|
1554
|
+
```
|
1555
|
+
|
1556
|
+
*Expect `a` to receive `:b` message 2 or more times:*
|
1557
|
+
|
1558
|
+
```ruby
|
1559
|
+
expect(a).to_receive(:b).count {|n| n >= 2}
|
1560
|
+
```
|
1561
|
+
|
1562
|
+
|
1563
|
+
**↳ Amount on multiple expectations**
|
1564
|
+
|
1565
|
+
When multiple messages expected, `count` will receive an argument per each message.
|
1566
|
+
|
1567
|
+
*Expect `a` to receive `:x` message 2 times and `:y` message 5 times:*
|
1568
|
+
|
1569
|
+
```ruby
|
1570
|
+
expect(a).to_receive(:x, :y).count(2, 5)
|
1571
|
+
```
|
1572
|
+
|
1573
|
+
When all messages are expected to receive same amount of times, use a single argument.
|
1574
|
+
|
1575
|
+
*Expect `a` to receive `:x` and `:y` messages exactly 2 times each:*
|
1576
|
+
|
1577
|
+
```ruby
|
1578
|
+
expect(a).to_receive(:x, :y).count(2)
|
1579
|
+
```
|
1580
|
+
|
1581
|
+
*Expect `a` to receive `:x` message exactly 2 times and `:y` message at least once:*
|
1582
|
+
|
1583
|
+
```ruby
|
1584
|
+
expect(a).to_receive(:x, :y).count {|x,y| x == 2 && y > 1}
|
1585
|
+
```
|
1586
|
+
|
1587
|
+
|
1588
|
+
[⇧ Table of Contents](#docs)
|
1589
|
+
|
1590
|
+
#### ↳ Messages Order
|
1591
|
+
|
1592
|
+
Unlike RSpec, ordering in Minispec works only with multiple messages.
|
1593
|
+
|
1594
|
+
*Expect `a` to receive `:x`, `:y`, `:z` messages exactly in specified order:*
|
1595
|
+
|
1596
|
+
```ruby
|
1597
|
+
expect(a).to_receive(:x, :y, :z).ordered
|
1598
|
+
```
|
1599
|
+
|
1600
|
+
If given messages will be received in another order, the test will fail.
|
1601
|
+
|
1602
|
+
It is also possible to check whether same sequence of messages received N times.
|
1603
|
+
|
1604
|
+
*Expect `a` to receive `:x`, `:y` sequence exactly 2 times:*
|
1605
|
+
|
1606
|
+
```ruby
|
1607
|
+
expect(a).to_receive(:x, :y).ordered(2)
|
1608
|
+
```
|
1609
|
+
|
1610
|
+
for this test to pass following code expected to be executed:
|
1611
|
+
|
1612
|
+
```ruby
|
1613
|
+
a.x
|
1614
|
+
a.y
|
1615
|
+
a.x
|
1616
|
+
a.y
|
1617
|
+
```
|
1618
|
+
|
1619
|
+
if at least one message not received or received in wrong order, the test will fail.
|
1620
|
+
|
1621
|
+
When you need more flexibility on received sequence, use a block.
|
1622
|
+
|
1623
|
+
*Expect `a` to receive `:x`, `:y` sequence at least once:*
|
1624
|
+
|
1625
|
+
```ruby
|
1626
|
+
expect(a).to_receive(:x, :y).ordered {|n| n >= 1}
|
1627
|
+
```
|
1628
|
+
|
1629
|
+
[⇧ Table of Contents](#docs)
|
1630
|
+
|
1631
|
+
|
1632
|
+
### Spies
|
1633
|
+
|
1634
|
+
Just like expectations, spies checks for some object to receive specific message(s). The only logical difference is that spies assumes message(s) was already received rather than expects they to be received in the future.
|
1635
|
+
|
1636
|
+
Also there is a technical difference - while expectations does not require any preparations on the objects, spies does. You should explicitly "attach a spy" on the object and specify what methods to spy on, let the object to behave in its way and only after that you can check whether it received expected messages.
|
1637
|
+
|
1638
|
+
Attaching a spy on a object is easily done via `spy` method.<br>
|
1639
|
+
Checking a message was received is done via `received` helper(or its sugar alias `received?`).
|
1640
|
+
|
1641
|
+
```ruby
|
1642
|
+
user = User.new
|
1643
|
+
spy(user, :location) # attaching spy...
|
1644
|
+
user.summary
|
1645
|
+
assert(user).received(:location) # checking location message received
|
1646
|
+
```
|
1647
|
+
|
1648
|
+
In terms of what happens after message received spies behaves exactly as expectations:
|
1649
|
+
|
1650
|
+
* checks arguments message(s) was received with
|
1651
|
+
* `with`
|
1652
|
+
* validates returned value(s)
|
1653
|
+
* `and_returned`
|
1654
|
+
* checks for raised errors
|
1655
|
+
* `and_raised`
|
1656
|
+
* checks for thrown symbols
|
1657
|
+
* `and_thrown`
|
1658
|
+
* validates yielded arguments
|
1659
|
+
* `and_yielded`
|
1660
|
+
* checks how many times message(s) was received
|
1661
|
+
* `count`
|
1662
|
+
* checks messages was received in specific order
|
1663
|
+
* `ordered`
|
1664
|
+
|
1665
|
+
|
1666
|
+
And just as with expectations, spies behaves well when dealing with multiple messages. Just attach a spy on multiple messages and validate them all at once:
|
1667
|
+
|
1668
|
+
```
|
1669
|
+
spy(user, :name, :age, :location)
|
1670
|
+
user.summary
|
1671
|
+
assert(user).received(:name, :age, :location)
|
1672
|
+
```
|
1673
|
+
|
1674
|
+
|
1675
|
+
[⇧ Table of Contents](#docs)
|
1676
|
+
|
1677
|
+
|
1678
|
+
### Stubs
|
1679
|
+
|
1680
|
+
Minispec allows to stub any method on a given object and have full control over stub behavior.
|
1681
|
+
|
1682
|
+
*Add `:x` stub:*
|
1683
|
+
|
1684
|
+
```ruby
|
1685
|
+
stub(some_object, :x)
|
1686
|
+
```
|
1687
|
+
|
1688
|
+
`some_object.x` will return `nil`.
|
1689
|
+
|
1690
|
+
When you need a stub to return some value, regardless given arguments, use a Hash or a block.
|
1691
|
+
|
1692
|
+
*Add `:x` stub and make it return `:y`:*
|
1693
|
+
|
1694
|
+
```ruby
|
1695
|
+
stub(some_object, :x => :y)
|
1696
|
+
```
|
1697
|
+
|
1698
|
+
`some_object.x` will return `:y`.
|
1699
|
+
|
1700
|
+
*Add `:x` stub and make it return `:z`:*
|
1701
|
+
|
1702
|
+
```ruby
|
1703
|
+
stub(some_object, :x) { :z }
|
1704
|
+
```
|
1705
|
+
|
1706
|
+
now `some_object.x` will return `:z`.
|
1707
|
+
|
1708
|
+
**Important!** Stubs does not impose any restrictions on arity, so stubbed methods can be called with any arguments!
|
1709
|
+
|
1710
|
+
Given arguments will just be passed into the block, preceded by the original. That's it, the block will receive the original method as first argument. If stubbed method were not defined on that object before stubbing, the block will receive `nil` as first argument.
|
1711
|
+
|
1712
|
+
Another important note is that method's visibility are kept even after they are stubbed. So if some method exists on target object and it is protected, the stub that will override original method will be protected as well.<br>
|
1713
|
+
Same for private and public methods.
|
1714
|
+
|
1715
|
+
And of course if we are stubbing some object that will still exists after test finished, the stubbed methods will be restored to their originals.
|
1716
|
+
|
1717
|
+
|
1718
|
+
[⇧ Table of Contents](#docs)
|
1719
|
+
|
1720
|
+
|
1721
|
+
#### ↳ Argument-vary stubs
|
1722
|
+
|
1723
|
+
Often you need a stub to behave in a way when receiving some arguments and another way when receiving another arguments.
|
1724
|
+
|
1725
|
+
At a first glance this could be done by comparing arguments inside the block:
|
1726
|
+
|
1727
|
+
*Bad!*
|
1728
|
+
|
1729
|
+
```ruby
|
1730
|
+
stub(some_object, :some_method) do |orig, *args|
|
1731
|
+
if args == [:a, :b]
|
1732
|
+
# do this
|
1733
|
+
elsif args == [:x, :y]
|
1734
|
+
# do that
|
1735
|
+
end
|
1736
|
+
end
|
1737
|
+
```
|
1738
|
+
|
1739
|
+
however this approach is tedious(at least) and really ugly.
|
1740
|
+
|
1741
|
+
Recommended way here is to use a block with each sequence of arguments.
|
1742
|
+
|
1743
|
+
For this to work you'd need to use `with` method.<br>
|
1744
|
+
It takes expected arguments and a block to be yielded when the stub called with given arguments:
|
1745
|
+
|
1746
|
+
```ruby
|
1747
|
+
stub(some_object, :some_method).
|
1748
|
+
with(:a, :b) { 'called with a, b' }.
|
1749
|
+
with(:x, :y) { 'called with x, y' }
|
1750
|
+
```
|
1751
|
+
|
1752
|
+
now `some_object.some_method(:a, :b)` will return 'called with a, b' and `some_object.some_method(:x, :y)` will return 'called with x, y'.
|
1753
|
+
|
1754
|
+
**However!** if called without arguments or with any arguments except [:a, :b] and [:x, :y], this example will actually return `nil`.
|
1755
|
+
|
1756
|
+
To define a "catchall" add one more block using `with_any`(or simply `any`):
|
1757
|
+
|
1758
|
+
```ruby
|
1759
|
+
stub(some_object, :some_method).
|
1760
|
+
with(:a, :b) { 'called with a, b' }.
|
1761
|
+
with(:x, :y) { 'called with x, y' }.
|
1762
|
+
with_any { 'whatever' }
|
1763
|
+
```
|
1764
|
+
|
1765
|
+
now when calling `some_method` **without arguments** or with **any arguments but** [:a, :b] and [:x, :y], it will return 'whatever'.
|
1766
|
+
|
1767
|
+
`with_any` can also be used with a value rather than a block. Also it can be placed anywhere in the chain, the order does not change the result:
|
1768
|
+
|
1769
|
+
```ruby
|
1770
|
+
stub(some_object, :some_method).
|
1771
|
+
with_any('whatever').
|
1772
|
+
with(:a, :b) { 'called with a, b' }.
|
1773
|
+
with(:x, :y) { 'called with x, y' }
|
1774
|
+
```
|
1775
|
+
|
1776
|
+
|
1777
|
+
**One more note:** if you prefer a more verbose style you can use `stub` method multiple times:
|
1778
|
+
|
1779
|
+
```ruby
|
1780
|
+
stub(some_object, :some_method).with(:a, :b) { 'called with a, b' }
|
1781
|
+
stub(some_object, :some_method).with(:x, :y) { 'called with x, y' }
|
1782
|
+
stub(some_object, :some_method).any { 'whatever' } # or `any('whatever')`
|
1783
|
+
```
|
1784
|
+
|
1785
|
+
this will work exactly the same way as chained syntax.
|
1786
|
+
|
1787
|
+
[⇧ Table of Contents](#docs)
|
1788
|
+
|
1789
|
+
|
1790
|
+
#### ↳ Stubbing multiple methods at once
|
1791
|
+
|
1792
|
+
Often you need to stub multiple methods and you feel that calling `stub` for each one is at least tedious.
|
1793
|
+
|
1794
|
+
And you will be right. Cause Minispec allows to add multiple stubs in one call. For this to work simply use `stubs` instead of `stub`.
|
1795
|
+
|
1796
|
+
*Stub `:x`, `:y` and `:z` methods on `cube`:*
|
1797
|
+
|
1798
|
+
```ruby
|
1799
|
+
stubs(cube, :x, :y, :z)
|
1800
|
+
```
|
1801
|
+
|
1802
|
+
**Worth to note** that given block will apply to all stubs.
|
1803
|
+
|
1804
|
+
*Stub `:x`, `:y` and `:z` methods on `cube` and make them all return the square of given value:*
|
1805
|
+
|
1806
|
+
```ruby
|
1807
|
+
stubs(cube, :x, :y, :z) {|orig, n| n ** 2}
|
1808
|
+
```
|
1809
|
+
|
1810
|
+
now `cube.x(2)` will return 4, `cube.y(4)` will return 16 etc.
|
1811
|
+
|
1812
|
+
Same for `with` and `with_any` methods - they apply to all stubbed methods without a way to different constraints for some stub:
|
1813
|
+
|
1814
|
+
```ruby
|
1815
|
+
stubs(a, :b, :c).
|
1816
|
+
with(1) {:one}.
|
1817
|
+
with(2) {:two}.
|
1818
|
+
with_any {:whatever}
|
1819
|
+
```
|
1820
|
+
|
1821
|
+
now both `a.b(1)` and `a.c(1)` will return :one, both `a.b(2)` and `a.c(2)` will return :two and any of `a.b`/`a.c` without arguments or with any arguments but 1 or 2 will return :whatever.
|
1822
|
+
|
1823
|
+
Also the method's visibility will be kept, so if some protected exists on target object, the stub will be protected as well. Same for private and public methods.
|
1824
|
+
|
1825
|
+
And of course multiple protected/private stubs can be defined by using `protected_stubs` and `private_stubs` accordingly.
|
1826
|
+
|
1827
|
+
|
1828
|
+
[⇧ Table of Contents](#docs)
|
1829
|
+
|
1830
|
+
|
1831
|
+
#### ↳ Chained stubs
|
1832
|
+
|
1833
|
+
When you need to stub a chain of methods in one statement use a string of dot separated methods:
|
1834
|
+
|
1835
|
+
```ruby
|
1836
|
+
stub(a, 'x.y.z')
|
1837
|
+
```
|
1838
|
+
|
1839
|
+
now `a.x.y.z` will work, though it will return `nil`.
|
1840
|
+
|
1841
|
+
When you need last method in the chain to return some value, use Hash or a block:
|
1842
|
+
|
1843
|
+
```ruby
|
1844
|
+
stub(a, 'b.c' => :z)
|
1845
|
+
```
|
1846
|
+
|
1847
|
+
now `a.b.c` will return `:z`.
|
1848
|
+
|
1849
|
+
```ruby
|
1850
|
+
stub(a, 'b.c') { :x }
|
1851
|
+
```
|
1852
|
+
|
1853
|
+
now `a.b.c` will return `:x`.
|
1854
|
+
|
1855
|
+
A important difference from regular stubs is that chained ones wont receive the original as first argument. They will only receive the arguments passed when stub called:
|
1856
|
+
|
1857
|
+
```ruby
|
1858
|
+
stub(a, 'b.c') {|x| x ** 2}
|
1859
|
+
a.b.c(4)
|
1860
|
+
# => 16
|
1861
|
+
```
|
1862
|
+
|
1863
|
+
If a block given when calling last method in the chain, it will be passed into the block alongside with any arguments. However you'll can not use `yield` here. You should receive it as argument and call it explicitly:
|
1864
|
+
|
1865
|
+
```ruby
|
1866
|
+
stub(a, 'b.c') do |n, block|
|
1867
|
+
block.call(n)
|
1868
|
+
end
|
1869
|
+
|
1870
|
+
a.b.c(4) {|y| y ** 2}
|
1871
|
+
# => 16
|
1872
|
+
```
|
1873
|
+
|
1874
|
+
|
1875
|
+
**Important!** just like regular stubs, chained ones may have arguments-vary behavior:
|
1876
|
+
|
1877
|
+
```ruby
|
1878
|
+
stub(a, 'b.c').
|
1879
|
+
with(1) {:one}.
|
1880
|
+
with(2) {:two}.
|
1881
|
+
with_any { :whatever }
|
1882
|
+
```
|
1883
|
+
|
1884
|
+
now `a.b.c(1)` will return :one and `a.b.c(2)` will return :two. If called without arguments or with any but 1 or 2, it will return :whatever.
|
1885
|
+
|
1886
|
+
**Worth to note** that chained stubs does not care about method visibility. It will always define a public singleton method on the target object:
|
1887
|
+
|
1888
|
+
So, `stub(a, 'b.c')` will define `b` public singleton method on `a`, even if `b` exists and it is protected/private.<br>
|
1889
|
+
That's the big difference from regular stubs where stubs keeps same visibility as original methods.
|
1890
|
+
|
1891
|
+
Please be aware that if the method to be stubbed already exists on the target object, it will be overridden for the time of test running and restored after the test finished.
|
1892
|
+
|
1893
|
+
|
1894
|
+
[⇧ Table of Contents](#docs)
|
1895
|
+
|
1896
|
+
|
1897
|
+
#### ↳ Calling original
|
1898
|
+
|
1899
|
+
If stubbed method already exists, the original method will be passed into block as first argument. Otherwise the block will receive `nil` as first argument.
|
1900
|
+
|
1901
|
+
```ruby
|
1902
|
+
stub(API, :request) do |original, *args, &block|
|
1903
|
+
# call the original with given args and block
|
1904
|
+
original.call(*args, &block)
|
1905
|
+
end
|
1906
|
+
```
|
1907
|
+
|
1908
|
+
`API.request` will call our stub which will then call the original.
|
1909
|
+
|
1910
|
+
|
1911
|
+
[⇧ Table of Contents](#docs)
|
1912
|
+
|
1913
|
+
|
1914
|
+
#### ↳ Stubs visibility
|
1915
|
+
|
1916
|
+
Keeping the SUT(system under test) in nearly same state as it would act in a real environment is a high priority matter for Minispec.
|
1917
|
+
|
1918
|
+
That's why when it is stubbing methods it is keeping original method visibility. Meant if a method were protected before stubbing, the stub will be protected as well. Same for private and public methods.
|
1919
|
+
|
1920
|
+
However if you want to enforce specific visibility on stubbed method, use one of `public_stub`, `protected_stub` or `private_stub`.<br>
|
1921
|
+
They will define a stub with a specific visibility regardless the visibility of original method.
|
1922
|
+
|
1923
|
+
And of course there are their counterparts for multiple stubbing: `public_stubs`, `protected_stubs` or `private_stubs`.
|
1924
|
+
|
1925
|
+
|
1926
|
+
[⇧ Table of Contents](#docs)
|
1927
|
+
|
1928
|
+
|
1929
|
+
### Mocks
|
1930
|
+
|
1931
|
+
Basically a mock is a mix of a stub and a expectation. Meant that you do not need to separately stub a method then add an expectation on it. Mocks doing this automatically.
|
1932
|
+
|
1933
|
+
*Stub method `:x` and ensure it will be called by the end of test:*
|
1934
|
+
|
1935
|
+
```ruby
|
1936
|
+
mock(some_object, :x)
|
1937
|
+
```
|
1938
|
+
|
1939
|
+
that's it.
|
1940
|
+
|
1941
|
+
This is a replacement for:
|
1942
|
+
|
1943
|
+
```ruby
|
1944
|
+
stub(some_object, :x)
|
1945
|
+
expect(some_object).to_receive(:x)
|
1946
|
+
```
|
1947
|
+
|
1948
|
+
**Worth to note** that expectations added by mocks are very basic ones, they will only expect message to be received. That's it, no arguments constraints, no returned value validation etc. If you need a more complex expectation you'll have to define it explicitly.
|
1949
|
+
|
1950
|
+
**Another important note:** `mock` method will actually return a stub, so you have full control over stubbed method's behavior.
|
1951
|
+
|
1952
|
+
*Mock method `:x` by making it return `:one` when called with 1:*
|
1953
|
+
|
1954
|
+
```ruby
|
1955
|
+
mock(some_object, :x).with(1) { :one }
|
1956
|
+
```
|
1957
|
+
|
1958
|
+
*Mock method `:x` by making it return `:one` when called with 1 and return 'whatever' when called with any other arguments or without arguments at all:*
|
1959
|
+
|
1960
|
+
```ruby
|
1961
|
+
mock(some_object, :x).
|
1962
|
+
with(1) { :one }.
|
1963
|
+
with_any { 'whatever' }
|
1964
|
+
```
|
1965
|
+
|
1966
|
+
|
1967
|
+
**Mocks also works with Hashes.**
|
1968
|
+
|
1969
|
+
*Mock method `:a` to return `:x` and method `:b` to return `:y`:*
|
1970
|
+
|
1971
|
+
```ruby
|
1972
|
+
mock(some_object, :a => :x, :b => :x)
|
1973
|
+
```
|
1974
|
+
|
1975
|
+
And as with stubs you can not use arguments filters when mocked methods given as a Hash.<br>
|
1976
|
+
This will raise an ArgumentError: `mock(some_object, :a => :x).with(...) {...}`.<br>
|
1977
|
+
Same for `with_any`.
|
1978
|
+
|
1979
|
+
|
1980
|
+
There is also a way to **mock multiple methods at once.**
|
1981
|
+
|
1982
|
+
For this simply use `mocks` instead of `mock`.
|
1983
|
+
|
1984
|
+
*Mock `:a` and `:b` methods:*
|
1985
|
+
|
1986
|
+
```ruby
|
1987
|
+
mock(some_object, :a, :b)
|
1988
|
+
```
|
1989
|
+
|
1990
|
+
for this to pass both `some_object.a` and `some_object.b` should be called.
|
1991
|
+
|
1992
|
+
When mocking multiple methods, the returned value will apply to all methods.
|
1993
|
+
|
1994
|
+
*Mock `:a` and `:b` and make them both to return `:x`:*
|
1995
|
+
|
1996
|
+
```ruby
|
1997
|
+
mock(some_object, :a, :b) { :x }
|
1998
|
+
```
|
1999
|
+
|
2000
|
+
There is no way to have specific setups when mocking multiple methods, that's it, all of them will behave the same way.
|
2001
|
+
|
2002
|
+
*Mock `:a` and `:b` and make them both to return `:one` when called with argument 1 and return `:two` when called with argument 2:*
|
2003
|
+
|
2004
|
+
```ruby
|
2005
|
+
mock(some_object, :a, :b).
|
2006
|
+
with(1) { :one }.
|
2007
|
+
with(2) { :two }
|
2008
|
+
```
|
2009
|
+
|
2010
|
+
|
2011
|
+
**Mocks visibility rules** works the same as for stubs. If some protected method are mocked, the mocked version will be protected as well. Same for private and public methods.
|
2012
|
+
|
2013
|
+
However when you need a mock to be of specific visibility, use one of `public_mock`, `protected_mock` or `private_mock`.
|
2014
|
+
|
2015
|
+
And of course there are their counterparts for multiple mocking: `public_mocks`, `protected_mocks` or `private_mocks`.
|
2016
|
+
|
2017
|
+
|
2018
|
+
One **significant difference** between mocks and stubs is that mocks does not support chained methods. That's it, you can not do like this: `mock(some_object, 'a.b.c')`. Instead you should stub the chain then explicitly define expectations:
|
2019
|
+
|
2020
|
+
```ruby
|
2021
|
+
stub(some_object, 'a.b.c')
|
2022
|
+
expect(some_object).to_receive(:a)
|
2023
|
+
expect(some_object.a).to_receive(:b)
|
2024
|
+
# ...
|
2025
|
+
```
|
2026
|
+
|
2027
|
+
|
2028
|
+
[⇧ Table of Contents](#docs)
|
2029
|
+
|
2030
|
+
|
2031
|
+
### Doubles
|
2032
|
+
|
2033
|
+
During testing you may need entities that behaves like some "real" objects.
|
2034
|
+
|
2035
|
+
Let's say you need to ensure a welcome email is sent to user after account creation.
|
2036
|
+
|
2037
|
+
Rather than create a full-blown mail object you can use a double that behaves like a mailer, e.g. responds to `deliver`.
|
2038
|
+
|
2039
|
+
To create a double simply use the `double` method:
|
2040
|
+
|
2041
|
+
```ruby
|
2042
|
+
email = 'bob@bobsen.com'
|
2043
|
+
|
2044
|
+
# creating mailer double
|
2045
|
+
mailer = double(:mailer, deliver: true)
|
2046
|
+
|
2047
|
+
# ensuring `deliver` will be called with user's email
|
2048
|
+
expect(mailer).to_receive(:deliver).with(user.email)
|
2049
|
+
|
2050
|
+
# injecting double into system
|
2051
|
+
User.new!(email: email, mailer: mailer)
|
2052
|
+
```
|
2053
|
+
|
2054
|
+
For this contrived test to pass, `mailer#deliver` should be called under the hood.
|
2055
|
+
|
2056
|
+
If one or more arguments given to `double` method, first argument will be used as name(unless it is a Hash). Double's name turns to be very helpful on failures output, so a real name will output rather than `#<Object...` notation.
|
2057
|
+
|
2058
|
+
[⇧ Table of Contents](#docs)
|
2059
|
+
|
2060
|
+
|
2061
|
+
## Running Specs
|
2062
|
+
|
2063
|
+
Minispec will look for specs in `./spec` and `./test` folders.
|
2064
|
+
|
2065
|
+
Any files that match `*_spec.rb`, `*_test.rb` or `test_*.rb` will be loaded by Minispec.
|
2066
|
+
|
2067
|
+
So if you go standard way and put name you spec files like this and put them in `spec` or `test` folder, all you need to run specs is to call `minispec` in you terminal:
|
2068
|
+
|
2069
|
+
```bash
|
2070
|
+
$ minispec
|
2071
|
+
```
|
2072
|
+
|
2073
|
+
If you want to test only some files, pass them as space delimited arguments:
|
2074
|
+
|
2075
|
+
```bash
|
2076
|
+
$ minispec spec/user_spec.rb spec/cart_spec.rb
|
2077
|
+
```
|
2078
|
+
|
2079
|
+
If you need to run specs from a script, use `Minispec.run`.
|
2080
|
+
|
2081
|
+
*Rakefile*
|
2082
|
+
|
2083
|
+
```ruby
|
2084
|
+
require 'minispec'
|
2085
|
+
desc 'Run all tests'
|
2086
|
+
task :test do
|
2087
|
+
Minispec.run
|
2088
|
+
end
|
2089
|
+
```
|
2090
|
+
|
2091
|
+
`run` accepts `pattern` option, so you can instruct Minispec on how to load your specs:
|
2092
|
+
|
2093
|
+
|
2094
|
+
```ruby
|
2095
|
+
require 'minispec'
|
2096
|
+
|
2097
|
+
namespace :test do
|
2098
|
+
|
2099
|
+
desc 'Run user tests'
|
2100
|
+
task :users do
|
2101
|
+
Minispec.run(pattern: 'test/**/user*.rb')
|
2102
|
+
end
|
2103
|
+
end
|
2104
|
+
```
|
2105
|
+
|
2106
|
+
|
2107
|
+
Also `:file` option accepted so you can run a single file:
|
2108
|
+
|
2109
|
+
```ruby
|
2110
|
+
require 'minispec'
|
2111
|
+
|
2112
|
+
Dir['test/**/test_*.rb'].each do |file|
|
2113
|
+
name = file.sub(/test\/test_(.+)\.rb/, '\1')
|
2114
|
+
desc 'Run %s tests' % name
|
2115
|
+
task 'test:' + name do
|
2116
|
+
Minispec.run(file: file)
|
2117
|
+
end
|
2118
|
+
end
|
2119
|
+
```
|
2120
|
+
|
2121
|
+
|
2122
|
+
[⇧ Table of Contents](#docs)
|
2123
|
+
|
2124
|
+
|
2125
|
+
## Contributors
|
2126
|
+
|
2127
|
+
Want to contribute? Great! Contributors highly wanted and welcome!
|
2128
|
+
|
2129
|
+
1. Fork it
|
2130
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
2131
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
2132
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
2133
|
+
5. Create new Pull Request
|
2134
|
+
|
2135
|
+
|
2136
|
+
## License
|
2137
|
+
|
2138
|
+
Copyright © 2014 Slee Woo <mail@sleewoo.com>
|
2139
|
+
|
2140
|
+
Distributed under the **[MIT License](https://github.com/sleewoo/minispec/blob/master/LICENSE)**
|