rr 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +3 -0
- data/README +7 -0
- data/Rakefile +1 -1
- data/examples/rr/probe_creator_example.rb +12 -0
- data/examples/rr/scenario_example.rb +34 -0
- data/lib/rr/probe_creator.rb +17 -6
- data/lib/rr/scenario.rb +39 -15
- metadata +2 -2
data/CHANGES
CHANGED
data/README
CHANGED
@@ -25,6 +25,13 @@ renders the partial.
|
|
25
25
|
|
26
26
|
view = controller.template
|
27
27
|
probe(view).render(:partial => "user_info")
|
28
|
+
|
29
|
+
Probes also support after_call callbacks. This is useful for Stubbing out
|
30
|
+
a class method and getting its return value. For example, using ActiveRecord:
|
31
|
+
|
32
|
+
probe(User).find('5') do |user|
|
33
|
+
mock(user).valid? {false}
|
34
|
+
end
|
28
35
|
|
29
36
|
== Block Syntax
|
30
37
|
script = MyScript.new
|
data/Rakefile
CHANGED
@@ -78,6 +78,18 @@ describe ProbeCreator, "#method_missing" do
|
|
78
78
|
@subject.foobar(1, 2).should == :baz
|
79
79
|
proc {@subject.foobar(1, 2)}.should raise_error(Errors::TimesCalledError)
|
80
80
|
end
|
81
|
+
|
82
|
+
it "sets after_call on the scenario when passed a block" do
|
83
|
+
real_value = Object.new
|
84
|
+
(class << @subject; self; end).class_eval do
|
85
|
+
define_method(:foobar) {real_value}
|
86
|
+
end
|
87
|
+
@creator.foobar(1, 2) {|value| mock(value).a_method {99}}
|
88
|
+
|
89
|
+
return_value = @subject.foobar(1, 2)
|
90
|
+
return_value.should === return_value
|
91
|
+
return_value.a_method.should == 99
|
92
|
+
end
|
81
93
|
end
|
82
94
|
|
83
95
|
end
|
@@ -195,6 +195,40 @@ describe Scenario, "#yields" do
|
|
195
195
|
end
|
196
196
|
end
|
197
197
|
|
198
|
+
describe Scenario, "#after_call" do
|
199
|
+
it_should_behave_like "RR::Scenario"
|
200
|
+
|
201
|
+
it "returns self" do
|
202
|
+
@scenario.after_call {}.should === @scenario
|
203
|
+
end
|
204
|
+
|
205
|
+
it "receives the return value in the block" do
|
206
|
+
return_value = {}
|
207
|
+
@scenario.returns(return_value).after_call do |value|
|
208
|
+
value[:foo] = :bar
|
209
|
+
end
|
210
|
+
|
211
|
+
actual_value = @scenario.call
|
212
|
+
actual_value.should === return_value
|
213
|
+
actual_value.should == {:foo => :bar}
|
214
|
+
end
|
215
|
+
|
216
|
+
it "allows after_call to mock the return value" do
|
217
|
+
return_value = Object.new
|
218
|
+
@scenario.with_any_args.returns(return_value).after_call do |value|
|
219
|
+
mock(value).inner_method(1) {:baz}
|
220
|
+
end
|
221
|
+
|
222
|
+
@object.foobar.inner_method(1).should == :baz
|
223
|
+
end
|
224
|
+
|
225
|
+
it "raises an error when not passed a block" do
|
226
|
+
proc do
|
227
|
+
@scenario.after_call
|
228
|
+
end.should raise_error(ArgumentError, "after_call expects a block")
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
198
232
|
describe Scenario, "#returns" do
|
199
233
|
it_should_behave_like "RR::Scenario"
|
200
234
|
|
data/lib/rr/probe_creator.rb
CHANGED
@@ -3,15 +3,24 @@ module RR
|
|
3
3
|
# a Scenario that acts like a probe.
|
4
4
|
#
|
5
5
|
# The following example probes method_name with arg1 and arg2
|
6
|
-
# returning
|
6
|
+
# returning the actual value of the method. The block is an after callback
|
7
|
+
# that intercepts the return value. Mocks or other modifications can
|
8
|
+
# be done to the return value.
|
7
9
|
#
|
8
|
-
# probe(subject).method_name(arg1, arg2) { return_value }
|
10
|
+
# probe(subject).method_name(arg1, arg2) { |return_value| }
|
9
11
|
#
|
10
|
-
# The ProbeCreator also supports a block sytnax.
|
12
|
+
# The ProbeCreator also supports a block sytnax. The block accepts
|
13
|
+
# a after_call callback, instead of a return value as with MockCreator
|
14
|
+
# and StubCreator.
|
11
15
|
#
|
12
|
-
# probe(
|
13
|
-
# m.
|
16
|
+
# probe(User) do |m|
|
17
|
+
# m.find('4') do |user|
|
18
|
+
# mock(user).valid? {false}
|
19
|
+
# end
|
14
20
|
# end
|
21
|
+
#
|
22
|
+
# user = User.find('4')
|
23
|
+
# user.valid? # false
|
15
24
|
class ProbeCreator
|
16
25
|
instance_methods.each { |m| undef_method m unless m =~ /^__/ }
|
17
26
|
|
@@ -22,10 +31,12 @@ module RR
|
|
22
31
|
end
|
23
32
|
|
24
33
|
protected
|
25
|
-
def method_missing(method_name, *args, &
|
34
|
+
def method_missing(method_name, *args, &after_call)
|
26
35
|
double = @space.create_double(@subject, method_name)
|
27
36
|
scenario = @space.create_scenario(double)
|
28
37
|
scenario.with(*args).once.implemented_by(double.original_method)
|
38
|
+
scenario.after_call(&after_call) if after_call
|
39
|
+
scenario
|
29
40
|
end
|
30
41
|
end
|
31
42
|
end
|
data/lib/rr/scenario.rb
CHANGED
@@ -11,6 +11,7 @@ module RR
|
|
11
11
|
@argument_expectation = nil
|
12
12
|
@times_called_expectation = nil
|
13
13
|
@times_called = 0
|
14
|
+
@after_call = nil
|
14
15
|
@yields = nil
|
15
16
|
end
|
16
17
|
|
@@ -114,6 +115,37 @@ module RR
|
|
114
115
|
@ordered
|
115
116
|
end
|
116
117
|
|
118
|
+
# Scenario#yields sets the Scenario to invoke a passed in block when
|
119
|
+
# the Scenario is called.
|
120
|
+
# An Expection will be raised if no block is passed in when the
|
121
|
+
# Scenario is called.
|
122
|
+
#
|
123
|
+
# Passing in a block sets the return value.
|
124
|
+
#
|
125
|
+
# mock(subject).method_name.yields(yield_arg1, yield_arg2) {return_value}
|
126
|
+
# subject.method_name {|yield_arg1, yield_arg2|}
|
127
|
+
def yields(*args, &returns)
|
128
|
+
@yields = args
|
129
|
+
returns(&returns) if returns
|
130
|
+
self
|
131
|
+
end
|
132
|
+
|
133
|
+
# Scenario#after_call creates a callback that occurs after call
|
134
|
+
# is called. The passed in block receives the return value of
|
135
|
+
# the Scenario being called.
|
136
|
+
# An Expection will be raised if no block is passed in.
|
137
|
+
#
|
138
|
+
# mock(subject).method_name {return_value}.after_call {|return_value|}
|
139
|
+
# subject.method_name # return_value
|
140
|
+
#
|
141
|
+
# This feature is built into probes.
|
142
|
+
# probe(User).find('1') {|user| mock(user).valid? {false}}
|
143
|
+
def after_call(&block)
|
144
|
+
raise ArgumentError, "after_call expects a block" unless block
|
145
|
+
@after_call = block
|
146
|
+
self
|
147
|
+
end
|
148
|
+
|
117
149
|
# Scenario#returns accepts an argument value or a block.
|
118
150
|
# It will raise an ArgumentError if both are passed in.
|
119
151
|
#
|
@@ -130,21 +162,6 @@ module RR
|
|
130
162
|
end
|
131
163
|
end
|
132
164
|
|
133
|
-
# Scenario#yields sets the Scenario to invoke a passed in block when
|
134
|
-
# the Scenario is called.
|
135
|
-
# An Expection will be raised if no block is passed in when the
|
136
|
-
# Scenario is called.
|
137
|
-
#
|
138
|
-
# Passing in a block sets the return value.
|
139
|
-
#
|
140
|
-
# mock(subject).method_name.yields(yield_arg1, yield_arg2) {return_value}
|
141
|
-
# subject.method_name {|yield_arg1, yield_arg2|}
|
142
|
-
def yields(*args, &returns)
|
143
|
-
@yields = args
|
144
|
-
returns(&returns) if returns
|
145
|
-
self
|
146
|
-
end
|
147
|
-
|
148
165
|
# Scenario#implemented_by sets the implementation of the Scenario.
|
149
166
|
# This method takes a Proc or a Method. Passing in a Method allows
|
150
167
|
# the Scenario to accept blocks.
|
@@ -165,6 +182,12 @@ module RR
|
|
165
182
|
# A TimesCalledError is raised when the times called
|
166
183
|
# exceeds the expected TimesCalledExpectation.
|
167
184
|
def call(*args, &block)
|
185
|
+
return_value = call_implementation(*args, &block)
|
186
|
+
@after_call.call(return_value) if @after_call
|
187
|
+
return_value
|
188
|
+
end
|
189
|
+
|
190
|
+
def call_implementation(*args, &block)
|
168
191
|
@times_called_expectation.verify_input if @times_called_expectation
|
169
192
|
@space.verify_ordered_scenario(self) if ordered?
|
170
193
|
if @yields
|
@@ -182,6 +205,7 @@ module RR
|
|
182
205
|
return @implementation.call(*args)
|
183
206
|
end
|
184
207
|
end
|
208
|
+
protected :call_implementation
|
185
209
|
|
186
210
|
# Scenario#exact_match? returns true when the passed in arguments
|
187
211
|
# exactly match the ArgumentEqualityError arguments.
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.3
|
|
3
3
|
specification_version: 1
|
4
4
|
name: rr
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.1.
|
7
|
-
date: 2007-07-
|
6
|
+
version: 0.1.6
|
7
|
+
date: 2007-07-10 00:00:00 -07:00
|
8
8
|
summary: RR (Double Ruby) is a double framework that features a rich selection of double techniques and a terse syntax. http://xunitpatterns.com/Test%20Double.html
|
9
9
|
require_paths:
|
10
10
|
- lib
|