rspec-mocks 2.8.0.rc1 → 2.8.0.rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2006 David Chelimsky, The RSpec Development Team
4
+ Copyright (c) 2005 Steven Baker
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,37 +1,254 @@
1
1
  # RSpec Mocks
2
2
 
3
- rspec-mocks provides a test-double framework for rspec including support
4
- for method stubs, fakes, and message expectations.
3
+ rspec-mocks is a test-double framework for rspec with support for method stubs,
4
+ fakes, and message expectations on generated test-doubles and real objects
5
+ alike.
5
6
 
6
7
  ## Install
7
8
 
8
9
  gem install rspec # for rspec-core, rspec-expectations, rspec-mocks
9
10
  gem install rspec-mocks # for rspec-mocks only
10
11
 
12
+ ## Test Doubles
13
+
14
+ A Test Double is an object that stands in for a real object in a test.
15
+ RSpec creates test doubles that support method stubs and message
16
+ expectations.
17
+
18
+ ```ruby
19
+ book = double("book")
20
+ ```
21
+
11
22
  ## Method Stubs
12
23
 
13
- describe "consumer" do
14
- it "gets stuff from a service" do
15
- service = double('service')
16
- service.stub(:find) { 'value' }
17
- consumer = Consumer.new(service)
18
- consumer.consume
19
- consumer.aquired_stuff.should eq(['value'])
20
- end
21
- end
24
+ A method stub is an implementation that returns a pre-determined value. Method
25
+ stubs can be declared on test doubles or real objects using the same syntax.
26
+ rspec-mocks supports 3 forms for declaring method stubs:
27
+
28
+ ```ruby
29
+ book.stub(:title) { "The RSpec Book" }
30
+ book.stub(:title => "The RSpec Book")
31
+ book.stub(:title).and_return("The RSpec Book")
32
+ ```
33
+
34
+ You can also use this shortcut, which creates a test double and declares a
35
+ method stub in one statement:
36
+
37
+ ```ruby
38
+ book = double("book", :title => "The RSpec Book")
39
+ ```
40
+
41
+ The first argment is a name, which is used for documentation and appears in
42
+ failure messages. If you don't care about the name, you can leave it out,
43
+ making the combined instantiation/stub declaration very terse:
44
+
45
+ ```ruby
46
+ double(:foo => 'bar')
47
+ ```
48
+
49
+ This is particularly nice when providing a list of test doubles to a method
50
+ that iterates through them:
51
+
52
+ ```ruby
53
+ order.calculate_total_price(stub(:price => 1.99),stub(:price => 2.99))
54
+ ```
55
+
56
+ ## Consecutive return values
57
+
58
+ When a stub might be invoked more than once, you can provide additional
59
+ arguments to `and_return`. The invocations cycle through the list. The last
60
+ value is returned for any subsequent invocations:
61
+
62
+ ```ruby
63
+ die.stub(:roll).and_return(1,2,3)
64
+ die.roll # => 1
65
+ die.roll # => 2
66
+ die.roll # => 3
67
+ die.roll # => 3
68
+ die.roll # => 3
69
+ ```
70
+
71
+ To return an array in a single invocation, declare an array:
72
+
73
+ ```ruby
74
+ team.stub(:players).and_return([stub(:name => "David")])
75
+ ```
22
76
 
23
77
  ## Message Expectations
24
78
 
25
- describe "some action" do
26
- context "when bad stuff happens" do
27
- it "logs the error" do
28
- logger = double('logger')
29
- doer = Doer.new(logger)
30
- logger.should_receive(:log).with('oops')
31
- doer.do_something_with(:bad_data)
32
- end
33
- end
34
- end
79
+ A message expectation is an expectation that the test double will receive a
80
+ message some time before the example ends. If the message is received, the
81
+ expectation is satisfied. If not, the example fails.
82
+
83
+ ```ruby
84
+ validator = double("validator")
85
+ validator.should_receive(:validate).with("02134")
86
+ zipcode = Zipcode.new("02134", validator)
87
+ zipcode.valid?
88
+ ```
89
+
90
+ ## Nomenclature
91
+
92
+ ### Mock Objects and Test Stubs
93
+
94
+ The names Mock Object and Test Stub suggest specialized Test Doubles. i.e.
95
+ a Test Stub is a Test Double that only supports method stubs, and a Mock
96
+ Object is a Test Double that supports message expectations and method
97
+ stubs.
98
+
99
+ There is a lot of overlapping nomenclature here, and there are many
100
+ variations of these patterns (fakes, spies, etc). Keep in mind that most of
101
+ the time we're talking about method-level concepts that are variations of
102
+ method stubs and message expectations, and we're applying to them to _one_
103
+ generic kind of object: a Test Double.
104
+
105
+ ### Test-Specific Extension
106
+
107
+ a.k.a. Partial Stub/Mock, a Test-Specific Extension is an extension of a
108
+ real object in a system that is instrumented with test-double like
109
+ behaviour in the context of a test. This technique is very common in Ruby
110
+ because we often see class objects acting as global namespaces for methods.
111
+ For example, in Rails:
112
+
113
+ ```ruby
114
+ person = double("person")
115
+ Person.stub(:find) { person }
116
+ ```
117
+
118
+ In this case we're instrumenting Person to return the person object we've
119
+ defined whenever it receives the `find` message. We can do this with any
120
+ object in a system because rspec-mocks adds the `stub` and `should_receive`
121
+ methods to every object. When we use either, RSpec replaces the method
122
+ we're stubbing or mocking with its own test-double-like method. At the
123
+ end of the example, RSpec verifies any message expectations, and then
124
+ restores the original methods.
125
+
126
+ ## Expecting Arguments
127
+
128
+ ```ruby
129
+ double.should_receive(:msg).with(*args)
130
+ double.should_not_receive(:msg).with(*args)
131
+ ```
132
+
133
+ ## Argument Matchers
134
+
135
+ Arguments that are passed to `with` are compared with actual arguments
136
+ received using ==. In cases in which you want to specify things about the
137
+ arguments rather than the arguments themselves, you can use any of the
138
+ matchers that ship with rspec-expectations. They don't all make syntactic
139
+ sense (they were primarily designed for use with RSpec::Expectations), but
140
+ you are free to create your own custom RSpec::Matchers.
141
+
142
+ rspec-mocks also adds some keyword Symbols that you can use to
143
+ specify certain kinds of arguments:
144
+
145
+ ```ruby
146
+ double.should_receive(:msg).with(no_args())
147
+ double.should_receive(:msg).with(any_args())
148
+ double.should_receive(:msg).with(1, kind_of(Numeric), "b") #2nd argument can any kind of Numeric
149
+ double.should_receive(:msg).with(1, boolean(), "b") #2nd argument can true or false
150
+ double.should_receive(:msg).with(1, /abc/, "b") #2nd argument can be any String matching the submitted Regexp
151
+ double.should_receive(:msg).with(1, anything(), "b") #2nd argument can be anything at all
152
+ double.should_receive(:msg).with(1, ducktype(:abs, :div), "b")
153
+ #2nd argument can be object that responds to #abs and #div
154
+ ```
155
+
156
+ ## Receive Counts
157
+
158
+ ```ruby
159
+ double.should_receive(:msg).once
160
+ double.should_receive(:msg).twice
161
+ double.should_receive(:msg).exactly(n).times
162
+ double.should_receive(:msg).at_least(:once)
163
+ double.should_receive(:msg).at_least(:twice)
164
+ double.should_receive(:msg).at_least(n).times
165
+ double.should_receive(:msg).at_most(:once)
166
+ double.should_receive(:msg).at_most(:twice)
167
+ double.should_receive(:msg).at_most(n).times
168
+ double.should_receive(:msg).any_number_of_times
169
+ ```
170
+
171
+ ## Ordering
172
+
173
+ ```ruby
174
+ double.should_receive(:msg).ordered
175
+ double.should_receive(:other_msg).ordered
176
+ #This will fail if the messages are received out of order
177
+ ```
178
+
179
+ ## Setting Reponses
180
+
181
+ Whether you are setting a message expectation or a method stub, you can
182
+ tell the object precisely how to respond. The most generic way is to pass
183
+ a block to `stub` or `should_receive`:
184
+
185
+ ```ruby
186
+ double.should_receive(:msg) { value }
187
+ ```
188
+
189
+ When the double receives the `msg` message, it evaluates the block and returns
190
+ the result.
191
+
192
+ ```ruby
193
+ double.should_receive(:msg).and_return(value)
194
+ double.should_receive(:msg).exactly(3).times.and_return(value1, value2, value3)
195
+ # returns value1 the first time, value2 the second, etc
196
+ double.should_receive(:msg).and_raise(error)
197
+ #error can be an instantiated object or a class
198
+ #if it is a class, it must be instantiable with no args
199
+ double.should_receive(:msg).and_throw(:msg)
200
+ double.should_receive(:msg).and_yield(values,to,yield)
201
+ double.should_receive(:msg).and_yield(values,to,yield).and_yield(some,other,values,this,time)
202
+ # for methods that yield to a block multiple times
203
+ ```
204
+
205
+ Any of these responses can be applied to a stub as well
206
+
207
+ ```ruby
208
+ double.stub(:msg).and_return(value)
209
+ double.stub(:msg).and_return(value1, value2, value3)
210
+ double.stub(:msg).and_raise(error)
211
+ double.stub(:msg).and_throw(:msg)
212
+ double.stub(:msg).and_yield(values,to,yield)
213
+ double.stub(:msg).and_yield(values,to,yield).and_yield(some,other,values,this,time)
214
+ ```
215
+
216
+ ## Arbitrary Handling
217
+
218
+ Once in a while you'll find that the available expectations don't solve the
219
+ particular problem you are trying to solve. Imagine that you expect the message
220
+ to come with an Array argument that has a specific length, but you don't care
221
+ what is in it. You could do this:
222
+
223
+ ```ruby
224
+ double.should_receive(:msg) do |arg|
225
+ arg.size.should eq(7)
226
+ end
227
+ ```
228
+
229
+ ## Combining Expectation Details
230
+
231
+ Combining the message name with specific arguments, receive counts and responses
232
+ you can get quite a bit of detail in your expectations:
233
+
234
+ ```ruby
235
+ double.should_receive(:<<).with("illegal value").once.and_raise(ArgumentError)
236
+ ```
237
+
238
+ While this is a good thing when you really need it, you probably don't really
239
+ need it! Take care to specify only the things that matter to the behavior of
240
+ your code.
241
+
242
+ ## Further Reading
243
+
244
+ There are many different viewpoints about the meaning of mocks and stubs. If
245
+ you are interested in learning more, here is some recommended reading:
246
+
247
+ * Mock Objects: http://www.mockobjects.com/
248
+ * Endo-Testing: http://www.mockobjects.com/files/endotesting.pdf
249
+ * Mock Roles, Not Objects: http://www.mockobjects.com/files/mockrolesnotobjects.pdf
250
+ * Test Double Patterns: http://xunitpatterns.com/Test%20Double%20Patterns.html
251
+ * Mocks aren't stubs: http://www.martinfowler.com/articles/mocksArentStubs.html
35
252
 
36
253
  ## Also see
37
254
 
@@ -1,184 +1,15 @@
1
1
  require 'rspec/mocks/framework'
2
2
  require 'rspec/mocks/version'
3
- require 'rspec/mocks/spec_methods'
3
+ require 'rspec/mocks/example_methods'
4
4
 
5
5
  module RSpec
6
- # == Test Doubles
7
- #
8
- # A Test Double is an object that stands in for a real object in a test.
9
- # RSpec creates test doubles that support method stubs and message
10
- # expectations.
11
- #
12
- # book = double("book")
13
- #
14
- # == Method Stubs
15
- #
16
- # A method stub is an implementation that returns a pre-determined value.
17
- #
18
- # book = double("book")
19
- # double.stub(:title) { "The RSpec Book" }
20
- # double.title # => "The RSpec Book"
21
- #
22
- # When we declare a stub, we say we are "stubbing" a method.
23
- #
24
- # == Message Expectations
25
- #
26
- # A message expectation is an expectation that the test double will receive a
27
- # message some time before the example ends. If the message is received, the
28
- # expectation is satisfied. If not, the example fails.
29
- #
30
- # validator = double("validator")
31
- # validator.should_receive(:validate).with("02134")
32
- # zipcode = Zipcode.new("02134", validator)
33
- # zipcode.valid?
34
- #
35
- # When we declare a message expectation, we say we are "mocking" a method.
36
- #
37
- # == Mock Objects and Test Stubs
38
- #
39
- # The names Mock Object and Test Stub suggest specialized Test Doubles. i.e.
40
- # a Test Stub is a Test Double that only supports method stubs, and a Mock
41
- # Object is a Test Double that supports message expectations and method
42
- # stubs.
43
- #
44
- # There is a lot of overlapping nomenclature here, and there are many
45
- # variations of these patterns (fakes, spies, etc). Keep in mind that most of
46
- # the time we're talking about method-level concepts that are variations of
47
- # method stubs and message expectations, and we're applying to them to _one_
48
- # generic kind of object: a Test Double.
49
- #
50
- # == Test-Specific Extension
51
- #
52
- # a.k.a. Partial Stub/Mock, a Test-Specific Extension is an extension of a
53
- # real object in a system that is instrumented with test-double like
54
- # behaviour in the context of a test. This technique is very common in Ruby
55
- # because we often see class objects acting as global namespaces for methods.
56
- # For example, in Rails:
57
- #
58
- # person = double("person")
59
- # Person.stub(:find) { person }
60
- #
61
- # In this case we're instrumenting Person to return the person object we've
62
- # defined whenever it receives the +find+ message. We can do this with any
63
- # object in a system because rspec-mocks adds the +stub+ and +should_receive+
64
- # methods to every object. When we use either, RSpec replaces the method
65
- # we're stubbing or mocking with it's own test-double-like method. At the
66
- # end of the example, RSpec verifies any message expectations, and then
67
- # restores the original methods.
68
- #
69
- # == Expecting Arguments
70
- #
71
- # double.should_receive(:msg).with(*args)
72
- # double.should_not_receive(:msg).with(*args)
73
- #
74
- # == Argument Matchers
75
- #
76
- # Arguments that are passed to +with+ are compared with actual arguments
77
- # received using ==. In cases in which you want to specify things about the
78
- # arguments rather than the arguments themselves, you can use any of the
79
- # matchers that ship with rspec-expectations. They don't all make syntactic
80
- # sense (they were primarily designed for use with RSpec::Expectations), but
81
- # you are free to create your own custom RSpec::Matchers.
82
- #
83
- # rspec-mocks also adds some keyword Symbols that you can use to
84
- # specify certain kinds of arguments:
85
- #
86
- # double.should_receive(:msg).with(no_args())
87
- # double.should_receive(:msg).with(any_args())
88
- # double.should_receive(:msg).with(1, kind_of(Numeric), "b") #2nd argument can any kind of Numeric
89
- # double.should_receive(:msg).with(1, boolean(), "b") #2nd argument can true or false
90
- # double.should_receive(:msg).with(1, /abc/, "b") #2nd argument can be any String matching the submitted Regexp
91
- # double.should_receive(:msg).with(1, anything(), "b") #2nd argument can be anything at all
92
- # double.should_receive(:msg).with(1, ducktype(:abs, :div), "b")
93
- # #2nd argument can be object that responds to #abs and #div
94
- #
95
- # == Receive Counts
96
- #
97
- # double.should_receive(:msg).once
98
- # double.should_receive(:msg).twice
99
- # double.should_receive(:msg).exactly(n).times
100
- # double.should_receive(:msg).at_least(:once)
101
- # double.should_receive(:msg).at_least(:twice)
102
- # double.should_receive(:msg).at_least(n).times
103
- # double.should_receive(:msg).at_most(:once)
104
- # double.should_receive(:msg).at_most(:twice)
105
- # double.should_receive(:msg).at_most(n).times
106
- # double.should_receive(:msg).any_number_of_times
107
- #
108
- # == Ordering
109
- #
110
- # double.should_receive(:msg).ordered
111
- # double.should_receive(:other_msg).ordered
112
- # #This will fail if the messages are received out of order
113
- #
114
- # == Setting Reponses
115
- #
116
- # Whether you are setting a message expectation or a method stub, you can
117
- # tell the object precisely how to respond. The most generic way is to pass
118
- # a block to +stub+ or +should_receive+:
119
- #
120
- # double.should_receive(:msg) { value }
121
- #
122
- # When the double receives the +msg+ message, it evaluates the block and returns
123
- # the result.
124
- #
125
- # double.should_receive(:msg).and_return(value)
126
- # double.should_receive(:msg).exactly(3).times.and_return(value1, value2, value3)
127
- # # returns value1 the first time, value2 the second, etc
128
- # double.should_receive(:msg).and_raise(error)
129
- # #error can be an instantiated object or a class
130
- # #if it is a class, it must be instantiable with no args
131
- # double.should_receive(:msg).and_throw(:msg)
132
- # double.should_receive(:msg).and_yield(values,to,yield)
133
- # double.should_receive(:msg).and_yield(values,to,yield).and_yield(some,other,values,this,time)
134
- # # for methods that yield to a block multiple times
135
- #
136
- # Any of these responses can be applied to a stub as well
137
- #
138
- # double.stub(:msg).and_return(value)
139
- # double.stub(:msg).and_return(value1, value2, value3)
140
- # double.stub(:msg).and_raise(error)
141
- # double.stub(:msg).and_throw(:msg)
142
- # double.stub(:msg).and_yield(values,to,yield)
143
- # double.stub(:msg).and_yield(values,to,yield).and_yield(some,other,values,this,time)
144
- #
145
- # == Arbitrary Handling
146
- #
147
- # Once in a while you'll find that the available expectations don't solve the
148
- # particular problem you are trying to solve. Imagine that you expect the message
149
- # to come with an Array argument that has a specific length, but you don't care
150
- # what is in it. You could do this:
151
- #
152
- # double.should_receive(:msg) do |arg|
153
- # arg.should be_an_istance_of(Array)
154
- # arg.length.should eq 7
155
- # end
156
- #
157
- # == Combining Expectation Details
158
- #
159
- # Combining the message name with specific arguments, receive counts and responses
160
- # you can get quite a bit of detail in your expectations:
161
- #
162
- # double.should_receive(:<<).with("illegal value").once.and_raise(ArgumentError)
163
- #
164
- # == Further Reading
165
- #
166
- # There are many different viewpoints about the meaning of mocks and stubs. If you are interested
167
- # in learning more, here is some recommended reading:
168
- #
169
- # * Mock Objects: http://www.mockobjects.com/
170
- # * Endo-Testing: http://www.mockobjects.com/files/endotesting.pdf
171
- # * Mock Roles, Not Objects: http://www.mockobjects.com/files/mockrolesnotobjects.pdf
172
- # * Test Double Patterns: http://xunitpatterns.com/Test%20Double%20Patterns.html
173
- # * Mocks aren't stubs: http://www.martinfowler.com/articles/mocksArentStubs.html
174
6
  module Mocks
175
7
  class << self
176
8
  attr_accessor :space
177
9
 
178
- def setup(includer)
179
- Object.class_eval { include RSpec::Mocks::Methods }
180
- Class.class_eval { include RSpec::Mocks::AnyInstance }
181
- (class << includer; self; end).class_eval do
10
+ def setup(host)
11
+ add_extensions unless extensions_added?
12
+ (class << host; self; end).class_eval do
182
13
  include RSpec::Mocks::ExampleMethods
183
14
  end
184
15
  self.space ||= RSpec::Mocks::Space.new
@@ -191,6 +22,18 @@ module RSpec
191
22
  def teardown
192
23
  space.reset_all
193
24
  end
25
+
26
+ private
27
+
28
+ def add_extensions
29
+ Object.class_eval { include RSpec::Mocks::Methods }
30
+ Class.class_eval { include RSpec::Mocks::AnyInstance }
31
+ $_rspec_mocks_extensions_added = true
32
+ end
33
+
34
+ def extensions_added?
35
+ defined?($_rspec_mocks_extensions_added)
36
+ end
194
37
  end
195
38
  end
196
39
  end