rspec-mocks 2.8.0.rc1 → 2.8.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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