much-stub 0.1.1 → 0.1.2
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.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/README.md +223 -39
- data/lib/much-stub.rb +14 -12
- data/lib/much-stub/version.rb +1 -1
- data/much-stub.gemspec +3 -3
- data/test/helper.rb +3 -3
- data/test/support/factory.rb +1 -2
- data/test/system/much-stub_tests.rb +204 -223
- data/test/unit/much-stub_tests.rb +96 -94
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 948b3a6fa21e50a2a221b167fe768a5d65c7a61c135622fe6ced882a5e406b03
|
4
|
+
data.tar.gz: 700d700fab285da4620cb4fbd3b521a58a9ffeaf8d50afdcc96780810091e301
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fecb7b76d76bc9ff338461c7ec6a48ac3bf1833bd77f4f248c9d4a145fa0b0177b3ce9d99d01add632266d7f9c5731441f0ad553f14775e7cf704aaffc80099a
|
7
|
+
data.tar.gz: 55308114a2f7aac2294ba44aac2adf84152cc2213a40a9ff0118b3fe2e8d43738cbc617fb19855c63515e915bc46754fc915d86b568d7a9c97356fb619420156
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -16,69 +16,253 @@ Note: this was originally implemented in and extracted from [Assert](https://git
|
|
16
16
|
```ruby
|
17
17
|
# Given this object/API
|
18
18
|
|
19
|
-
|
20
|
-
def
|
21
|
-
|
19
|
+
my_class = Class.new do
|
20
|
+
def my_method
|
21
|
+
"my-method"
|
22
|
+
end
|
23
|
+
|
24
|
+
def my_value(value)
|
25
|
+
value
|
26
|
+
end
|
22
27
|
end
|
23
|
-
|
28
|
+
my_object = my_class.new
|
24
29
|
|
25
|
-
|
26
|
-
# =>
|
27
|
-
|
30
|
+
my_object.my_method
|
31
|
+
# => "my-method"
|
32
|
+
my_object.my_value(123)
|
28
33
|
# => 123
|
29
|
-
|
34
|
+
my_object.my_value(456)
|
30
35
|
# => 456
|
31
36
|
|
32
|
-
# Create a new stub for the :
|
37
|
+
# Create a new stub for the :my_method method
|
33
38
|
|
34
|
-
MuchStub.(
|
35
|
-
|
36
|
-
# => StubError: `
|
37
|
-
MuchStub.(
|
38
|
-
|
39
|
-
# =>
|
40
|
-
|
39
|
+
MuchStub.(my_object, :my_method)
|
40
|
+
my_object.my_method
|
41
|
+
# => StubError: `my_method` not stubbed.
|
42
|
+
MuchStub.(my_object, :my_method){ "stubbed-method" }
|
43
|
+
my_object.my_method
|
44
|
+
# => "stubbed-method"
|
45
|
+
my_object.my_method(123)
|
41
46
|
# => StubError: arity mismatch
|
42
|
-
MuchStub.(
|
47
|
+
MuchStub.(my_object, :my_method).with(123){ "stubbed-method" }
|
43
48
|
# => StubError: arity mismatch
|
44
|
-
MuchStub.stub_send(myobj, :mymeth) # call to the original method post-stub
|
45
|
-
# => 'meth'
|
46
49
|
|
47
|
-
#
|
50
|
+
# Call the original method after it has been stubbed.
|
51
|
+
|
52
|
+
MuchStub.stub_send(my_object, :my_method)
|
53
|
+
# => "my-method"
|
48
54
|
|
49
|
-
|
55
|
+
# Create a new stub for the :my_value method
|
56
|
+
|
57
|
+
MuchStub.(my_object, :my_value){ "stubbed-method" }
|
50
58
|
# => StubError: arity mismatch
|
51
|
-
MuchStub.(
|
52
|
-
|
59
|
+
MuchStub.(my_object, :my_value).with(123){ |val| val.to_s }
|
60
|
+
my_object.my_value
|
53
61
|
# => StubError: arity mismatch
|
54
|
-
|
55
|
-
# =>
|
56
|
-
|
57
|
-
# => StubError: `
|
62
|
+
my_object.my_value(123)
|
63
|
+
# => "123"
|
64
|
+
my_object.my_value(456)
|
65
|
+
# => StubError: `my_value(456)` not stubbed.
|
58
66
|
|
59
|
-
# Call
|
67
|
+
# Call the original method after it has been stubbed.
|
60
68
|
|
61
|
-
MuchStub.stub_send(
|
69
|
+
MuchStub.stub_send(my_object, :my_value, 123)
|
62
70
|
# => 123
|
63
|
-
MuchStub.stub_send(
|
71
|
+
MuchStub.stub_send(my_object, :my_value, 456)
|
64
72
|
# => 456
|
65
73
|
|
66
74
|
# Unstub individual stubs
|
67
75
|
|
68
|
-
MuchStub.unstub(
|
69
|
-
MuchStub.unstub(
|
76
|
+
MuchStub.unstub(my_object, :my_method)
|
77
|
+
MuchStub.unstub(my_object, :my_value)
|
70
78
|
|
71
79
|
# OR blanket unstub all stubs
|
72
80
|
|
73
81
|
MuchStub.unstub!
|
74
82
|
|
75
|
-
#
|
83
|
+
# The original API/behavior is preserved after unstubbing
|
76
84
|
|
77
|
-
|
78
|
-
# =>
|
79
|
-
|
85
|
+
my_object.my_method
|
86
|
+
# => "my-method"
|
87
|
+
my_object.my_value(123)
|
80
88
|
# => 123
|
81
|
-
|
89
|
+
my_object.my_value(456)
|
90
|
+
# => 456
|
91
|
+
```
|
92
|
+
|
93
|
+
### Stubs for spying
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
# Given this object/API
|
97
|
+
|
98
|
+
my_class = Class.new do
|
99
|
+
def basic_method(value)
|
100
|
+
value
|
101
|
+
end
|
102
|
+
|
103
|
+
def iterator_method(items, &block)
|
104
|
+
items.each(&block)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
my_object = my_class.new
|
108
|
+
|
109
|
+
# Store method call arguments/blocks for spying.
|
110
|
+
|
111
|
+
basic_method_called_with = nil
|
112
|
+
MuchStub.(my_object, :basic_method) { |*args|
|
113
|
+
basic_method_called_with = args
|
114
|
+
}
|
115
|
+
|
116
|
+
my_object.basic_method(123)
|
117
|
+
basic_method_called_with
|
118
|
+
# => [123]
|
119
|
+
|
120
|
+
iterator_method_call_args = nil
|
121
|
+
iterator_method_call_block = nil
|
122
|
+
MuchStub.(my_object, :iterator_method) { |*args, &block|
|
123
|
+
iterator_method_call_args = args
|
124
|
+
iterator_method_call_block = block
|
125
|
+
}
|
126
|
+
|
127
|
+
my_object.iterator_method([1, 2, 3], &:to_s)
|
128
|
+
iterator_method_call_args
|
129
|
+
# => [[1, 2, 3]]
|
130
|
+
iterator_method_call_block
|
131
|
+
# => #<Proc:0x00007fb083a6feb0(&:to_s)>
|
132
|
+
|
133
|
+
# Count method calls for spying.
|
134
|
+
|
135
|
+
basic_method_call_count = 0
|
136
|
+
MuchStub.(my_object, :basic_method) {
|
137
|
+
basic_method_call_count += 1
|
138
|
+
}
|
139
|
+
|
140
|
+
my_object.basic_method(123)
|
141
|
+
basic_method_call_count
|
142
|
+
# => 1
|
143
|
+
|
144
|
+
# Count method calls and store arguments for spying.
|
145
|
+
|
146
|
+
basic_method_calls = []
|
147
|
+
MuchStub.(my_object, :basic_method) { |*args|
|
148
|
+
basic_method_calls << args
|
149
|
+
}
|
150
|
+
|
151
|
+
my_object.basic_method(123)
|
152
|
+
basic_method_calls.size
|
153
|
+
# => 1
|
154
|
+
basic_method_calls.first
|
155
|
+
# => [123]
|
156
|
+
```
|
157
|
+
|
158
|
+
### Stubs for test doubles.
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
# Given this object/API ...
|
162
|
+
|
163
|
+
my_class = Class.new do
|
164
|
+
def build_thing(thing_value);
|
165
|
+
Thing.new(value)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
my_object = my_class.new
|
169
|
+
|
170
|
+
# ... and this Test Double.
|
171
|
+
class FakeThing
|
172
|
+
attr_reader :built_with
|
173
|
+
|
174
|
+
def initialize(*args)
|
175
|
+
@built_with = args
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# Stub in the test double.
|
180
|
+
|
181
|
+
MuchStub.(my_object, :build_thing) { |*args|
|
182
|
+
FakeThing.new(*args)
|
183
|
+
}
|
184
|
+
|
185
|
+
thing = my_object.build_thing(123)
|
186
|
+
thing.built_with
|
187
|
+
# => [123]
|
188
|
+
```
|
189
|
+
|
190
|
+
### `MuchStub.tap`
|
191
|
+
|
192
|
+
Use the `.tap` method to spy on method calls while preserving the original method return value and behavior.
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
# Given this object/API
|
196
|
+
|
197
|
+
my_class = Class.new do
|
198
|
+
def basic_method(value)
|
199
|
+
value.to_s
|
200
|
+
end
|
201
|
+
end
|
202
|
+
my_object = my_class.new
|
203
|
+
|
204
|
+
# Normal stubs override the original behavior and return value...
|
205
|
+
basic_method_called_with = nil
|
206
|
+
MuchStub.(my_object, :basic_method) { |*args|
|
207
|
+
basic_method_called_with = args
|
208
|
+
}
|
209
|
+
|
210
|
+
# ... in this case not converting the value to a String and returning it and
|
211
|
+
# instead returning the arguments passed to the method.
|
212
|
+
my_object.basic_method(123)
|
213
|
+
# => [123]
|
214
|
+
basic_method_called_with
|
215
|
+
# => [123]
|
216
|
+
|
217
|
+
# Use `MuchStub.tap` to preserve the methods behavior and also spy.
|
218
|
+
|
219
|
+
basic_method_called_with = nil
|
220
|
+
MuchStub.tap(my_object, :basic_method) { |value, *args|
|
221
|
+
basic_method_called_with = args
|
222
|
+
}
|
223
|
+
|
224
|
+
my_object.basic_method(123)
|
225
|
+
# => "123"
|
226
|
+
basic_method_called_with
|
227
|
+
# => [123]
|
228
|
+
```
|
229
|
+
|
230
|
+
#### Late-bound stubs using `MuchStub.tap`
|
231
|
+
|
232
|
+
Use the `.tap` method to stub any return values of method calls.
|
233
|
+
|
234
|
+
```ruby
|
235
|
+
# Given:
|
236
|
+
|
237
|
+
class Thing
|
238
|
+
attr_reader :value
|
239
|
+
|
240
|
+
def initialize(value)
|
241
|
+
@value = value
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
my_class = Class.new do
|
246
|
+
def thing(value)
|
247
|
+
Thing.new(value)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
my_object = my_class.new
|
251
|
+
|
252
|
+
# Use `MuchStub.tap` to stub any thing instances created by `my_object.thing`
|
253
|
+
# (and also spy on the call arguments)
|
254
|
+
|
255
|
+
thing_built_with = nil
|
256
|
+
MuchStub.tap(my_object, :thing) { |thing, *args|
|
257
|
+
thing_built_with = args
|
258
|
+
MuchStub.(thing, :value) { 456 }
|
259
|
+
}
|
260
|
+
|
261
|
+
thing = my_object.thing(123)
|
262
|
+
# => #<Thing:0x00007fd5ca9df510 @value=123>
|
263
|
+
thing_built_with
|
264
|
+
# => [123]
|
265
|
+
thing.value
|
82
266
|
# => 456
|
83
267
|
```
|
84
268
|
|
@@ -86,7 +270,7 @@ myobj.myval(456)
|
|
86
270
|
|
87
271
|
Add this line to your application's Gemfile:
|
88
272
|
|
89
|
-
gem
|
273
|
+
gem "much-stub"
|
90
274
|
|
91
275
|
And then execute:
|
92
276
|
|
@@ -100,6 +284,6 @@ Or install it yourself as:
|
|
100
284
|
|
101
285
|
1. Fork it
|
102
286
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
103
|
-
3. Commit your changes (`git commit -am
|
287
|
+
3. Commit your changes (`git commit -am "Added some feature"`)
|
104
288
|
4. Push to the branch (`git push origin my-new-feature`)
|
105
289
|
5. Create new Pull Request
|
data/lib/much-stub.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require "much-stub/version"
|
2
2
|
|
3
3
|
module MuchStub
|
4
|
-
|
5
4
|
def self.stubs
|
6
5
|
@stubs ||= {}
|
7
6
|
end
|
@@ -37,8 +36,15 @@ module MuchStub
|
|
37
36
|
stub.call_method(args, &block)
|
38
37
|
end
|
39
38
|
|
40
|
-
|
39
|
+
def self.tap(obj, meth, &tap_block)
|
40
|
+
self.stub(obj, meth) { |*args, &block|
|
41
|
+
self.stub_send(obj, meth, *args, &block).tap { |value|
|
42
|
+
tap_block.call(value, *args, &block) if tap_block
|
43
|
+
}
|
44
|
+
}
|
45
|
+
end
|
41
46
|
|
47
|
+
class Stub
|
42
48
|
def self.key(object, method_name)
|
43
49
|
"--#{object.object_id}--#{method_name}--"
|
44
50
|
end
|
@@ -100,7 +106,7 @@ module MuchStub
|
|
100
106
|
end
|
101
107
|
|
102
108
|
def inspect
|
103
|
-
"#<#{self.class}:#{
|
109
|
+
"#<#{self.class}:#{"0x0%x" % (object_id << 1)}" \
|
104
110
|
" @method_name=#{@method_name.inspect}" \
|
105
111
|
">"
|
106
112
|
end
|
@@ -159,7 +165,7 @@ module MuchStub
|
|
159
165
|
end
|
160
166
|
|
161
167
|
def inspect_call(args)
|
162
|
-
"`#{@method_name}(#{args.map(&:inspect).join(
|
168
|
+
"`#{@method_name}(#{args.map(&:inspect).join(",")})`"
|
163
169
|
end
|
164
170
|
|
165
171
|
def number_of_args(arity)
|
@@ -169,7 +175,6 @@ module MuchStub
|
|
169
175
|
arity
|
170
176
|
end
|
171
177
|
end
|
172
|
-
|
173
178
|
end
|
174
179
|
|
175
180
|
StubError = Class.new(ArgumentError)
|
@@ -181,15 +186,14 @@ module MuchStub
|
|
181
186
|
end
|
182
187
|
|
183
188
|
module ParameterList
|
184
|
-
|
185
|
-
LETTERS = ('a'..'z').to_a.freeze
|
189
|
+
LETTERS = ("a".."z").to_a.freeze
|
186
190
|
|
187
191
|
def self.new(object, method_name)
|
188
192
|
arity = get_arity(object, method_name)
|
189
193
|
params = build_params_from_arity(arity)
|
190
|
-
params <<
|
191
|
-
params <<
|
192
|
-
params.join(
|
194
|
+
params << "*args" if arity < 0
|
195
|
+
params << "&block"
|
196
|
+
params.join(", ")
|
193
197
|
end
|
194
198
|
|
195
199
|
private
|
@@ -210,9 +214,7 @@ module MuchStub
|
|
210
214
|
number_of_letters, letter_index = param_index.divmod(LETTERS.size)
|
211
215
|
LETTERS[letter_index] * number_of_letters
|
212
216
|
end
|
213
|
-
|
214
217
|
end
|
215
|
-
|
216
218
|
end
|
217
219
|
|
218
220
|
# Kernel#caller_locations polyfill for pre ruby 2.0.0
|
data/lib/much-stub/version.rb
CHANGED
data/much-stub.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
4
|
require "much-stub/version"
|
5
5
|
|
@@ -11,13 +11,13 @@ Gem::Specification.new do |gem|
|
|
11
11
|
gem.summary = "Stubbing API for replacing method calls on objects in test runs."
|
12
12
|
gem.description = "Stubbing API for replacing method calls on objects in test runs."
|
13
13
|
gem.homepage = "https://github.com/redding/much-stub"
|
14
|
-
gem.license =
|
14
|
+
gem.license = "MIT"
|
15
15
|
|
16
16
|
gem.files = `git ls-files`.split($/)
|
17
17
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
18
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
19
|
gem.require_paths = ["lib"]
|
20
20
|
|
21
|
-
gem.add_development_dependency("assert", ["~> 2.
|
21
|
+
gem.add_development_dependency("assert", ["~> 2.18.0"])
|
22
22
|
|
23
23
|
end
|
data/test/helper.rb
CHANGED
@@ -5,9 +5,9 @@
|
|
5
5
|
$LOAD_PATH.unshift(File.expand_path("../..", __FILE__))
|
6
6
|
|
7
7
|
# require pry for debugging (`binding.pry`)
|
8
|
-
require
|
8
|
+
require "pry"
|
9
9
|
|
10
|
-
require
|
10
|
+
require "test/support/factory"
|
11
11
|
|
12
12
|
# 1.8.7 backfills
|
13
13
|
|
@@ -19,7 +19,7 @@ if !(a = Array.new).respond_to?(:sample) && a.respond_to?(:choice)
|
|
19
19
|
end
|
20
20
|
|
21
21
|
# unstub all test stubs automatically for Assert test suite
|
22
|
-
require
|
22
|
+
require "assert"
|
23
23
|
class Assert::Context
|
24
24
|
teardown{ MuchStub.unstub! }
|
25
25
|
end
|