@@ -4,7 +4,7 @@ rspec-core provides the structure for writing executable examples of how your
4
4
code should behave, and an ` rspec ` command with tools to constrain which
5
5
examples get run and tailor the output.
6
6
7
- ## install
7
+ ## Install
8
8
9
9
gem install rspec # for rspec-core, rspec-expectations, rspec-mocks
10
10
gem install rspec-core # for rspec-core only
@@ -14,12 +14,12 @@ Want to run against the `master` branch? You'll need to include the dependent
14
14
RSpec repos as well. Add the following to your ` Gemfile ` :
15
15
16
16
``` ruby
17
- %w[rspec-core rspec-expectations rspec-mocks rspec-support] .each do |lib |
17
+ %w[rspec rspec -core rspec-expectations rspec-mocks rspec-support] .each do |lib |
18
18
gem lib, :git => " git://github.com/rspec/#{ lib } .git" , :branch => ' master'
19
19
end
20
20
```
21
21
22
- ## basic structure
22
+ ## Basic Structure
23
23
24
24
RSpec uses the words "describe" and "it" so we can express concepts like a conversation:
25
25
@@ -30,13 +30,15 @@ RSpec uses the words "describe" and "it" so we can express concepts like a conve
30
30
RSpec .describe Order do
31
31
it " sums the prices of its line items" do
32
32
order = Order .new
33
+
33
34
order.add_entry(LineItem .new (:item => Item .new (
34
35
:price => Money .new (1.11 , :USD )
35
36
)))
36
37
order.add_entry(LineItem .new (:item => Item .new (
37
38
:price => Money .new (2.22 , :USD ),
38
39
:quantity => 2
39
40
)))
41
+
40
42
expect(order.total).to eq(Money .new (5.55 , :USD ))
41
43
end
42
44
end
@@ -49,7 +51,7 @@ Under the hood, an example group is a class in which the block passed to
49
51
` describe ` is evaluated. The blocks passed to ` it ` are evaluated in the
50
52
context of an _ instance_ of that class.
51
53
52
- ## nested groups
54
+ ## Nested Groups
53
55
54
56
You can also declare nested nested groups using the ` describe ` or ` context `
55
57
methods:
@@ -70,7 +72,10 @@ RSpec.describe Order do
70
72
end
71
73
```
72
74
73
- ## aliases
75
+ Nested groups are subclasses of the outer example group class, providing
76
+ the inheritance semantics you'd want for free.
77
+
78
+ ## Aliases
74
79
75
80
You can declare example groups using either ` describe ` or ` context ` .
76
81
For a top level example group, ` describe ` and ` context ` are available
@@ -81,7 +86,7 @@ patching.
81
86
You can declare examples within a group using any of ` it ` , ` specify ` , or
82
87
` example ` .
83
88
84
- ## shared examples and contexts
89
+ ## Shared Examples and Contexts
85
90
86
91
Declare a shared example group using ` shared_examples ` , and then include it
87
92
in any group using ` include_examples ` .
@@ -111,7 +116,7 @@ pretty much the same as `shared_examples` and `include_examples`, providing
111
116
more accurate naming when you share hooks, ` let ` declarations, helper methods,
112
117
etc, but no examples.
113
118
114
- ## metadata
119
+ ## Metadata
115
120
116
121
rspec-core stores a metadata hash with every example and group, which
117
122
contains their descriptions, the locations at which they were
@@ -162,26 +167,106 @@ RSpec.describe Hash do
162
167
end
163
168
```
164
169
165
- ## the ` rspec ` command
170
+ ## A Word on Scope
171
+
172
+ RSpec has two scopes:
173
+
174
+ * ** Example Group** : Example groups are defined by a ` describe ` or
175
+ ` context ` block, which is eagerly evaluated when the spec file is
176
+ loaded. The block is evaluated in the context of a subclass of
177
+ ` RSpec::Core::ExampleGroup ` , or a subclass of the parent example group
178
+ when you're nesting them.
179
+ * ** Example** : Examples -- typically defined by an ` it ` block -- and any other
180
+ blocks with per-example semantics -- such as a ` before(:example) ` hook -- are
181
+ evaluated in the context of
182
+ an _ instance_ of the example group class to which the example belongs.
183
+ Examples are _ not_ executed when the spec file is loaded; instead,
184
+ RSpec waits to run any examples until all spec files have been loaded,
185
+ at which point it can apply filtering, randomization, etc.
186
+
187
+ To make this more concrete, consider this code snippet:
188
+
189
+ ``` ruby
190
+ RSpec .describe " Using an array as a stack" do
191
+ def build_stack
192
+ []
193
+ end
194
+
195
+ before(:example ) do
196
+ @stack = build_stack
197
+ end
198
+
199
+ it ' is initially empty' do
200
+ expect(@stack ).to be_empty
201
+ end
202
+
203
+ context " after an item has been pushed" do
204
+ before(:example ) do
205
+ @stack .push :item
206
+ end
207
+
208
+ it ' allows the pushed item to be popped' do
209
+ expect(@stack .pop).to eq(:item )
210
+ end
211
+ end
212
+ end
213
+ ```
214
+
215
+ Under the covers, this is (roughly) equivalent to:
216
+
217
+ ``` ruby
218
+ class UsingAnArrayAsAStack < RSpec ::Core ::ExampleGroup
219
+ def build_stack
220
+ []
221
+ end
222
+
223
+ def before_example_1
224
+ @stack = build_stack
225
+ end
226
+
227
+ def it_is_initially_empty
228
+ expect(@stack ).to be_empty
229
+ end
230
+
231
+ class AfterAnItemHasBeenPushed < self
232
+ def before_example_2
233
+ @stack .push :item
234
+ end
235
+
236
+ def it_allows_the_pushed_item_to_be_popped
237
+ expect(@stack .pop).to eq(:item )
238
+ end
239
+ end
240
+ end
241
+ ```
242
+
243
+ To run these examples, RSpec would (roughly) do the following:
244
+
245
+ ``` ruby
246
+ example_1 = UsingAnArrayAsAStack .new
247
+ example_1.before_example_1
248
+ example_1.it_is_initially_empty
249
+
250
+ example_2 = UsingAnArrayAsAStack ::AfterAnItemHasBeenPushed .new
251
+ example_2.before_example_1
252
+ example_2.before_example_2
253
+ example_2.it_allows_the_pushed_item_to_be_popped
254
+ ```
255
+
256
+ ## The ` rspec ` Command
166
257
167
258
When you install the rspec-core gem, it installs the ` rspec ` executable,
168
259
which you'll use to run rspec. The ` rspec ` command comes with many useful
169
260
options.
170
261
Run ` rspec --help ` to see the complete list.
171
262
172
- ## store command line options ` .rspec `
263
+ ## Store Command Line Options ` .rspec `
173
264
174
265
You can store command line options in a ` .rspec ` file in the project's root
175
266
directory, and the ` rspec ` command will read them as though you typed them on
176
267
the command line.
177
268
178
- ## autotest integration
179
-
180
- rspec-core no longer ships with an Autotest extension, if you require Autotest
181
- integration, please use the ` rspec-autotest ` gem and see [ rspec/rspec-autotest] ( https://github.com/rspec/rspec-autotest )
182
- for details
183
-
184
- ## get started
269
+ ## Get Started
185
270
186
271
Start with a simple example of behavior you expect from your system. Do
187
272
this before you write any implementation code:
@@ -204,13 +289,12 @@ $ rspec spec/calculator_spec.rb
204
289
./spec/calculator_spec.rb:1: uninitialized constant Calculator
205
290
```
206
291
207
- Implement the simplest solution :
292
+ Address the failure by defining a skeleton of the ` Calculator ` class :
208
293
209
294
``` ruby
210
295
# in lib/calculator.rb
211
296
class Calculator
212
- def add (a ,b )
213
- a + b
297
+ def add (a , b )
214
298
end
215
299
end
216
300
```
@@ -223,6 +307,39 @@ Be sure to require the implementation file in the spec:
223
307
require " calculator"
224
308
```
225
309
310
+ Now run the spec again, and watch the expectation fail:
311
+
312
+ ```
313
+ $ rspec spec/calculator_spec.rb
314
+ F
315
+
316
+ Failures:
317
+
318
+ 1) Calculator#add returns the sum of its arguments
319
+ Failure/Error: expect(Calculator.new.add(1, 2)).to eq(3)
320
+
321
+ expected: 3
322
+ got: nil
323
+
324
+ (compared using ==)
325
+ # ./spec/calcalator_spec.rb:6:in `block (3 levels) in <top (required)>'
326
+
327
+ Finished in 0.00131 seconds (files took 0.10968 seconds to load)
328
+ 1 example, 1 failure
329
+
330
+ Failed examples:
331
+
332
+ rspec ./spec/calcalator_spec.rb:5 # Calculator#add returns the sum of its arguments
333
+ ```
334
+
335
+ Implement the simplest solution, by changing the definition of ` Calculator#add ` to:
336
+
337
+ ``` ruby
338
+ def add (a , b )
339
+ a + b
340
+ end
341
+ ```
342
+
226
343
Now run the spec again, and watch it pass:
227
344
228
345
```
0 commit comments