soveran-override 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +3 -2
- data/lib/override.rb +1 -60
- data/test/all_test.rb +59 -20
- metadata +1 -1
data/README.markdown
CHANGED
@@ -49,7 +49,7 @@ It is a common pattern to set expectations for method calls. You can do
|
|
49
49
|
it with the `expect` function:
|
50
50
|
|
51
51
|
user = User.spawn :name => "Foobar"
|
52
|
-
expect(User, :find, :
|
52
|
+
expect(User, :find, :with => [:first, { :include => :friendships }], :return => user)
|
53
53
|
|
54
54
|
And then:
|
55
55
|
|
@@ -68,7 +68,8 @@ of calls received by the redefined method. The RSpec equivalent of
|
|
68
68
|
triggers an exception if the method is not called. While it is a handy
|
69
69
|
feature, it encourages coupling and testing internals, so my advice
|
70
70
|
would be to use it scarcely and to try to refactor your code so it
|
71
|
-
doesn't follow this testing anti-pattern.
|
71
|
+
doesn't follow this testing anti-pattern. Check the tests for more
|
72
|
+
examples.
|
72
73
|
|
73
74
|
Installation
|
74
75
|
------------
|
data/lib/override.rb
CHANGED
@@ -1,60 +1,3 @@
|
|
1
|
-
# Override
|
2
|
-
#
|
3
|
-
# This is the pure esence of the stubbing concept: it takes an object,
|
4
|
-
# a hash of methods/results, and proceeds to rewrite each method in the
|
5
|
-
# object. It can be used as a stubbing strategy in most cases, and I'd
|
6
|
-
# say that cases that don't fit this pattern have a very bad code smell,
|
7
|
-
# because are either dealing with internals or with side effects.
|
8
|
-
#
|
9
|
-
# Usage
|
10
|
-
#
|
11
|
-
# require 'override'
|
12
|
-
#
|
13
|
-
# @user = User.spawn
|
14
|
-
# override(@user, :name => "Foobar", :email => "foobar@example.org")
|
15
|
-
# override(User, :find => @user)
|
16
|
-
#
|
17
|
-
# Or alternatively:
|
18
|
-
#
|
19
|
-
# override(User, :find => override(User.spawn, :name => "Foobar, :email => "foobar@example.org"))
|
20
|
-
#
|
21
|
-
# In case you don't know what spawn means, check my other library for
|
22
|
-
# testing at http://github.com/soveran/spawner.
|
23
|
-
#
|
24
|
-
# Note: the arity strictness in Ruby 1.9 demands for that trick that
|
25
|
-
# drops the arguments passed to the redefined method. It's not necessary
|
26
|
-
# in Ruby 1.8.
|
27
|
-
#
|
28
|
-
# You can also send lambdas that will become the body of the redefined method:
|
29
|
-
#
|
30
|
-
# user = User.spawn :name => "Foobar"
|
31
|
-
# override(User, :find => lambda { |id| raise ArgumentError unless id == 1; user })
|
32
|
-
#
|
33
|
-
# And then, in your tests:
|
34
|
-
#
|
35
|
-
# assert_raise ArgumentError do
|
36
|
-
# User.find(2)
|
37
|
-
# end
|
38
|
-
#
|
39
|
-
# assert_nothing_raised do
|
40
|
-
# User.find(1)
|
41
|
-
# end
|
42
|
-
#
|
43
|
-
# assert_equal "Foobar", User.find(1).name
|
44
|
-
#
|
45
|
-
# It is a common pattern to set expectations for method calls. You can
|
46
|
-
# do it with the expect function:
|
47
|
-
#
|
48
|
-
# user = User.spawn :name => "Foobar"
|
49
|
-
# expect(User, :find, :return => user, :params => [:first, { :include => :friendships }])
|
50
|
-
#
|
51
|
-
# And then:
|
52
|
-
#
|
53
|
-
# assert_equal "Foobar", User.find(:first, :include => :friendships).name
|
54
|
-
# assert_raise ArgumentError do
|
55
|
-
# User.find(:all)
|
56
|
-
# end
|
57
|
-
#
|
58
1
|
require "rubygems"
|
59
2
|
require "metaid"
|
60
3
|
|
@@ -64,15 +7,13 @@ def override object, methods
|
|
64
7
|
object.meta_def(method, &result.to_proc) :
|
65
8
|
object.meta_def(method) { |*_| result }
|
66
9
|
end
|
67
|
-
|
68
10
|
object
|
69
11
|
end
|
70
12
|
|
71
13
|
def expect object, method, options
|
72
14
|
expectation = lambda do |*params|
|
73
|
-
raise ArgumentError unless params == options[:
|
15
|
+
raise ArgumentError unless params == options[:with]
|
74
16
|
options[:return]
|
75
17
|
end
|
76
|
-
|
77
18
|
override(object, method => expectation)
|
78
19
|
end
|
data/test/all_test.rb
CHANGED
@@ -17,11 +17,22 @@ class Foo
|
|
17
17
|
"Qux"
|
18
18
|
end
|
19
19
|
|
20
|
+
def nom
|
21
|
+
Bar.foo(1, 2, 3)
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
20
25
|
def == other
|
21
26
|
bar == other.bar
|
22
27
|
end
|
23
28
|
end
|
24
29
|
|
30
|
+
class Bar
|
31
|
+
def self.foo(a, b, c)
|
32
|
+
"Bar/Foo"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
25
36
|
class Callable
|
26
37
|
def to_proc
|
27
38
|
lambda do |name|
|
@@ -37,11 +48,11 @@ class TestOverride < Test::Unit::TestCase
|
|
37
48
|
override(@foo, :bar => "Hello")
|
38
49
|
end
|
39
50
|
|
40
|
-
|
51
|
+
should "work without arguments" do
|
41
52
|
assert_equal "Hello", @foo.bar
|
42
53
|
end
|
43
54
|
|
44
|
-
|
55
|
+
should "discard arguments" do
|
45
56
|
assert_equal "Hello", @foo.bar(1)
|
46
57
|
end
|
47
58
|
end
|
@@ -52,17 +63,17 @@ class TestOverride < Test::Unit::TestCase
|
|
52
63
|
@foo2 = Foo.new
|
53
64
|
end
|
54
65
|
|
55
|
-
|
66
|
+
should "work for string returns" do
|
56
67
|
override(@foo, :bar => "Hello")
|
57
68
|
assert_equal "Hello", @foo.bar
|
58
69
|
end
|
59
70
|
|
60
|
-
|
71
|
+
should "work for numeric returns" do
|
61
72
|
override(@foo, :bar => 23)
|
62
73
|
assert_equal 23, @foo.bar
|
63
74
|
end
|
64
75
|
|
65
|
-
|
76
|
+
should "work for object returns" do
|
66
77
|
override(@foo, :bar => @foo2)
|
67
78
|
assert_equal @foo2, @foo.bar
|
68
79
|
end
|
@@ -73,19 +84,19 @@ class TestOverride < Test::Unit::TestCase
|
|
73
84
|
@foo = Foo.new
|
74
85
|
end
|
75
86
|
|
76
|
-
|
87
|
+
should "work for methods that used to receive blocks" do
|
77
88
|
override(@foo, :baz => "Hey!")
|
78
89
|
assert_equal "Hey!", @foo.baz { |x| x }
|
79
90
|
end
|
80
91
|
|
81
|
-
|
92
|
+
should "work for methods that used to receive arguments" do
|
82
93
|
override(@foo, :qux => "Yay!")
|
83
94
|
assert_equal "Yay!", @foo.qux(1, 2, 3)
|
84
95
|
end
|
85
96
|
end
|
86
97
|
|
87
98
|
context "rewriting multiple methods at once" do
|
88
|
-
|
99
|
+
should "override all the passed methods" do
|
89
100
|
override(@foo, :bar => 1, :baz => 2, :qux => 3)
|
90
101
|
assert_equal 1, @foo.bar
|
91
102
|
assert_equal 2, @foo.baz
|
@@ -94,13 +105,13 @@ class TestOverride < Test::Unit::TestCase
|
|
94
105
|
end
|
95
106
|
|
96
107
|
context "chaining successive calls" do
|
97
|
-
|
108
|
+
should "return the object and allow chained calls" do
|
98
109
|
assert_equal 1, override(@foo, :bar => 1).bar
|
99
110
|
end
|
100
111
|
end
|
101
112
|
|
102
113
|
context "dealing with a proc as the result value" do
|
103
|
-
|
114
|
+
should "uses the proc as the body of the method" do
|
104
115
|
override(@foo, :bar => lambda { |name| "Hello #{name}" })
|
105
116
|
assert_equal "Hello World", @foo.bar("World")
|
106
117
|
end
|
@@ -118,7 +129,7 @@ class TestOverride < Test::Unit::TestCase
|
|
118
129
|
override(@foo, :bar => lambda { |id| raise ArgumentError unless id == 1; user })
|
119
130
|
end
|
120
131
|
|
121
|
-
|
132
|
+
should "lambdas should be able to raise exceptions" do
|
122
133
|
assert_raise ArgumentError do
|
123
134
|
@foo.bar(2)
|
124
135
|
end
|
@@ -139,11 +150,11 @@ class TestOverride < Test::Unit::TestCase
|
|
139
150
|
override(@foo, :baz => lambda { @name })
|
140
151
|
end
|
141
152
|
|
142
|
-
|
153
|
+
should "succeeds when the lambda returns a local variable" do
|
143
154
|
assert_equal "Michel", @foo.bar
|
144
155
|
end
|
145
156
|
|
146
|
-
|
157
|
+
should "fails when the lambda is supposed to return an instance variable" do
|
147
158
|
assert_equal nil, @foo.baz
|
148
159
|
end
|
149
160
|
end
|
@@ -153,7 +164,7 @@ class TestOverride < Test::Unit::TestCase
|
|
153
164
|
override(@foo, :bar => Callable.new)
|
154
165
|
end
|
155
166
|
|
156
|
-
|
167
|
+
should "coerces the value into a proc" do
|
157
168
|
assert_equal "Hello World", @foo.bar("World")
|
158
169
|
end
|
159
170
|
end
|
@@ -163,23 +174,23 @@ class TestOverride < Test::Unit::TestCase
|
|
163
174
|
override(@foo, :bar => lambda { lambda { "Hey!" } })
|
164
175
|
end
|
165
176
|
|
166
|
-
|
177
|
+
should "returns a lambda if it's wraped inside a proc" do
|
167
178
|
assert_equal "Hey!", @foo.bar.call
|
168
179
|
end
|
169
180
|
end
|
170
181
|
|
171
182
|
context "setting expectations" do
|
172
183
|
setup do
|
173
|
-
expect(@foo, :bar, :
|
184
|
+
expect(@foo, :bar, :with => ["Michel", 32], :return => true)
|
174
185
|
end
|
175
186
|
|
176
|
-
|
187
|
+
should "raises an error if expectations are not met" do
|
177
188
|
assert_raise ArgumentError do
|
178
189
|
@foo.bar "Michel", 31
|
179
190
|
end
|
180
191
|
end
|
181
192
|
|
182
|
-
|
193
|
+
should "succeeds if expectations are met" do
|
183
194
|
assert_nothing_raised do
|
184
195
|
@foo.bar "Michel", 32
|
185
196
|
end
|
@@ -188,13 +199,41 @@ class TestOverride < Test::Unit::TestCase
|
|
188
199
|
|
189
200
|
context "setting expectations with hashes in the param list" do
|
190
201
|
setup do
|
191
|
-
expect(@foo, :bar, :
|
202
|
+
expect(@foo, :bar, :with => ["Michel", { :include => :friendships, :select => "name" }], :return => true)
|
192
203
|
end
|
193
204
|
|
194
|
-
|
205
|
+
should "succeeds if expectations are met" do
|
195
206
|
assert_nothing_raised do
|
196
207
|
@foo.bar "Michel", { :select => "name", :include => :friendships, :select => "name" }
|
197
208
|
end
|
198
209
|
end
|
199
210
|
end
|
211
|
+
|
212
|
+
context "side effects" do
|
213
|
+
setup do
|
214
|
+
@foo = Foo.new
|
215
|
+
expect(Bar, :foo, :with => [1, 2, 3], :return => "Bar/Bar")
|
216
|
+
end
|
217
|
+
|
218
|
+
should "don't affect the interface" do
|
219
|
+
assert_equal true, @foo.nom
|
220
|
+
end
|
221
|
+
|
222
|
+
should "detect the method call as a side effect" do
|
223
|
+
override(Bar, :foo => lambda { |*_| raise ArgumentError })
|
224
|
+
assert_raise ArgumentError do
|
225
|
+
@foo.nom
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
should "don't affect the interfaces!" do
|
230
|
+
@foo = Foo.new
|
231
|
+
expect(Bar, :foo, :with => [1, 2, 3], :return => "Bar/Bar")
|
232
|
+
assert_equal true, @foo.nom
|
233
|
+
override(Bar, :foo => lambda { |*_| raise ArgumentError })
|
234
|
+
assert_raise ArgumentError do
|
235
|
+
@foo.nom
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
200
239
|
end
|