much-stub 0.1.0

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,447 @@
1
+ require 'assert'
2
+ require 'much-stub'
3
+
4
+ require 'test/support/factory'
5
+
6
+ module MuchStub
7
+
8
+ class UnitTests < Assert::Context
9
+ desc "MuchStub"
10
+ end
11
+
12
+ class ApiTests < UnitTests
13
+ desc "api"
14
+ setup do
15
+ @orig_value = Factory.string
16
+ @stub_value = Factory.string
17
+
18
+ @myclass = Class.new do
19
+ def initialize(value); @value = value; end
20
+ def mymeth; @value; end
21
+ end
22
+ @myobj = @myclass.new(@orig_value)
23
+ end
24
+
25
+ should "build a stub" do
26
+ stub1 = MuchStub.stub(@myobj, :mymeth)
27
+ assert_kind_of MuchStub::Stub, stub1
28
+ end
29
+
30
+ should "lookup stubs that have been called before" do
31
+ stub1 = MuchStub.stub(@myobj, :mymeth)
32
+ stub2 = MuchStub.stub(@myobj, :mymeth)
33
+ assert_same stub1, stub2
34
+ end
35
+
36
+ should "set the stub's do block if given a block" do
37
+ MuchStub.stub(@myobj, :mymeth)
38
+ assert_raises(MuchStub::NotStubbedError){ @myobj.mymeth }
39
+ MuchStub.stub(@myobj, :mymeth){ @stub_value }
40
+ assert_equal @stub_value, @myobj.mymeth
41
+ end
42
+
43
+ should "teardown stubs" do
44
+ assert_equal @orig_value, @myobj.mymeth
45
+ MuchStub.unstub(@myobj, :mymeth)
46
+ assert_equal @orig_value, @myobj.mymeth
47
+
48
+ assert_equal @orig_value, @myobj.mymeth
49
+ MuchStub.stub(@myobj, :mymeth){ @stub_value }
50
+ assert_equal @stub_value, @myobj.mymeth
51
+ MuchStub.unstub(@myobj, :mymeth)
52
+ assert_equal @orig_value, @myobj.mymeth
53
+ end
54
+
55
+ should "know and teardown all stubs" do
56
+ assert_equal @orig_value, @myobj.mymeth
57
+
58
+ MuchStub.stub(@myobj, :mymeth){ @stub_value }
59
+ assert_equal @stub_value, @myobj.mymeth
60
+ assert_equal 1, MuchStub.stubs.size
61
+
62
+ MuchStub.unstub!
63
+ assert_equal @orig_value, @myobj.mymeth
64
+ assert_empty MuchStub.stubs
65
+ end
66
+
67
+ should "be able to call a stub's original method" do
68
+ err = assert_raises(NotStubbedError){ MuchStub.stub_send(@myobj, :mymeth) }
69
+ assert_includes 'not stubbed.', err.message
70
+ assert_includes 'test/unit/much-stub_tests.rb', err.backtrace.first
71
+
72
+ MuchStub.stub(@myobj, :mymeth){ @stub_value }
73
+
74
+ assert_equal @stub_value, @myobj.mymeth
75
+ assert_equal @orig_value, MuchStub.stub_send(@myobj, :mymeth)
76
+ end
77
+
78
+ end
79
+
80
+ class StubTests < UnitTests
81
+ desc "Stub"
82
+ setup do
83
+ @myclass = Class.new do
84
+ def mymeth; 'meth'; end
85
+ def myval(val); val; end
86
+ def myargs(*args); args; end
87
+ def myvalargs(val1, val2, *args); [val1, val2, args]; end
88
+ def myblk(&block); block.call; end
89
+ end
90
+ @myobj = @myclass.new
91
+
92
+ @stub = MuchStub::Stub.new(@myobj, :mymeth)
93
+ end
94
+ subject{ @stub }
95
+
96
+ should have_readers :method_name, :name, :ivar_name, :do
97
+ should have_writers :do
98
+ should have_cmeths :key
99
+ should have_imeths :call_method, :call, :with, :teardown
100
+
101
+ should "generate a key given an object and method name" do
102
+ obj = @myobj
103
+ meth = :mymeth
104
+ assert_equal "--#{obj.object_id}--#{meth}--", MuchStub::Stub.key(obj, meth)
105
+ end
106
+
107
+ should "know its names" do
108
+ assert_equal 'mymeth', subject.method_name
109
+ expected = "__muchstub_stub__#{@myobj.object_id}_#{subject.method_name}"
110
+ assert_equal expected, subject.name
111
+ expected = "@__muchstub_stub_#{@myobj.object_id}_" \
112
+ "#{subject.method_name.to_sym.object_id}"
113
+ assert_equal expected, subject.ivar_name
114
+ end
115
+
116
+ should "complain when called if no do block was given" do
117
+ err = assert_raises(MuchStub::NotStubbedError){ @myobj.mymeth }
118
+ assert_includes 'not stubbed.', err.message
119
+ assert_includes 'test/unit/much-stub_tests.rb', err.backtrace.first
120
+
121
+ subject.do = proc{ 'mymeth' }
122
+ assert_nothing_raised do
123
+ @myobj.mymeth
124
+ end
125
+
126
+ assert_nothing_raised do
127
+ MuchStub::Stub.new(@myobj, :mymeth){ 'mymeth' }
128
+ end
129
+ end
130
+
131
+ should "complain if stubbing a method that the object doesn't respond to" do
132
+ err = assert_raises(MuchStub::StubError){ MuchStub::Stub.new(@myobj, :some_other_meth) }
133
+ assert_includes 'does not respond to', err.message
134
+ assert_includes 'test/unit/much-stub_tests.rb', err.backtrace.first
135
+ end
136
+
137
+ should "complain if stubbed and called with no `do` proc given" do
138
+ assert_raises(MuchStub::NotStubbedError){ @myobj.mymeth }
139
+ end
140
+
141
+ should "complain if stubbed and called with mismatched arity" do
142
+ MuchStub::Stub.new(@myobj, :myval){ 'myval' }
143
+ err = assert_raises(MuchStub::StubArityError){ @myobj.myval }
144
+ assert_includes 'arity mismatch on', err.message
145
+ assert_includes 'test/unit/much-stub_tests.rb', err.backtrace.first
146
+
147
+ assert_nothing_raised { @myobj.myval(1) }
148
+ assert_raises(MuchStub::StubArityError){ @myobj.myval(1,2) }
149
+
150
+ MuchStub::Stub.new(@myobj, :myargs){ 'myargs' }
151
+ assert_nothing_raised { @myobj.myargs }
152
+ assert_nothing_raised { @myobj.myargs(1) }
153
+ assert_nothing_raised { @myobj.myargs(1,2) }
154
+
155
+ MuchStub::Stub.new(@myobj, :myvalargs){ 'myvalargs' }
156
+ assert_raises(MuchStub::StubArityError){ @myobj.myvalargs }
157
+ assert_raises(MuchStub::StubArityError){ @myobj.myvalargs(1) }
158
+ assert_nothing_raised { @myobj.myvalargs(1,2) }
159
+ assert_nothing_raised { @myobj.myvalargs(1,2,3) }
160
+ end
161
+
162
+ should "complain if stubbed with mismatched arity" do
163
+ err = assert_raises(MuchStub::StubArityError) do
164
+ MuchStub::Stub.new(@myobj, :myval).with(){ 'myval' }
165
+ end
166
+ assert_includes 'arity mismatch on', err.message
167
+ assert_includes 'test/unit/much-stub_tests.rb', err.backtrace.first
168
+
169
+ assert_raises(MuchStub::StubArityError) do
170
+ MuchStub::Stub.new(@myobj, :myval).with(1,2){ 'myval' }
171
+ end
172
+ assert_nothing_raised do
173
+ MuchStub::Stub.new(@myobj, :myval).with(1){ 'myval' }
174
+ end
175
+
176
+ assert_nothing_raised do
177
+ MuchStub::Stub.new(@myobj, :myargs).with(){ 'myargs' }
178
+ end
179
+ assert_nothing_raised do
180
+ MuchStub::Stub.new(@myobj, :myargs).with(1,2){ 'myargs' }
181
+ end
182
+ assert_nothing_raised do
183
+ MuchStub::Stub.new(@myobj, :myargs).with(1){ 'myargs' }
184
+ end
185
+
186
+ assert_raises(MuchStub::StubArityError) do
187
+ MuchStub::Stub.new(@myobj, :myvalargs).with(){ 'myvalargs' }
188
+ end
189
+ assert_raises(MuchStub::StubArityError) do
190
+ MuchStub::Stub.new(@myobj, :myvalargs).with(1){ 'myvalargs' }
191
+ end
192
+ assert_nothing_raised do
193
+ MuchStub::Stub.new(@myobj, :myvalargs).with(1,2){ 'myvalargs' }
194
+ end
195
+ assert_nothing_raised do
196
+ MuchStub::Stub.new(@myobj, :myvalargs).with(1,2,3){ 'myvalargs' }
197
+ end
198
+ end
199
+
200
+ should "stub methods with no args" do
201
+ subject.teardown
202
+
203
+ assert_equal 'meth', @myobj.mymeth
204
+ MuchStub::Stub.new(@myobj, :mymeth){ 'mymeth' }
205
+ assert_equal 'mymeth', @myobj.mymeth
206
+ end
207
+
208
+ should "stub methods with required arg" do
209
+ assert_equal 1, @myobj.myval(1)
210
+ stub = MuchStub::Stub.new(@myobj, :myval){ |val| val.to_s }
211
+ assert_equal '1', @myobj.myval(1)
212
+ assert_equal '2', @myobj.myval(2)
213
+ stub.with(2){ 'two' }
214
+ assert_equal 'two', @myobj.myval(2)
215
+ end
216
+
217
+ should "stub methods with variable args" do
218
+ assert_equal [1,2], @myobj.myargs(1,2)
219
+ stub = MuchStub::Stub.new(@myobj, :myargs){ |*args| args.join(',') }
220
+ assert_equal '1,2', @myobj.myargs(1,2)
221
+ assert_equal '3,4,5', @myobj.myargs(3,4,5)
222
+ stub.with(3,4,5){ 'three-four-five' }
223
+ assert_equal 'three-four-five', @myobj.myargs(3,4,5)
224
+ end
225
+
226
+ should "stub methods with required args and variable args" do
227
+ assert_equal [1,2, [3]], @myobj.myvalargs(1,2,3)
228
+ stub = MuchStub::Stub.new(@myobj, :myvalargs){ |*args| args.join(',') }
229
+ assert_equal '1,2,3', @myobj.myvalargs(1,2,3)
230
+ assert_equal '3,4,5', @myobj.myvalargs(3,4,5)
231
+ stub.with(3,4,5){ 'three-four-five' }
232
+ assert_equal 'three-four-five', @myobj.myvalargs(3,4,5)
233
+ end
234
+
235
+ should "stub methods that yield blocks" do
236
+ blkcalled = false
237
+ blk = proc{ blkcalled = true }
238
+ @myobj.myblk(&blk)
239
+ assert_equal true, blkcalled
240
+
241
+ blkcalled = false
242
+ MuchStub::Stub.new(@myobj, :myblk){ blkcalled = 'true' }
243
+ @myobj.myblk(&blk)
244
+ assert_equal 'true', blkcalled
245
+ end
246
+
247
+ should "stub methods even if they are not local to the object" do
248
+ mydelegatorclass = Class.new do
249
+ def initialize(delegateclass)
250
+ @delegate = delegateclass.new
251
+ end
252
+ def respond_to?(meth)
253
+ @delegate.respond_to?(meth) || super
254
+ end
255
+ def method_missing(meth, *args, &block)
256
+ respond_to?(meth) ? @delegate.send(meth, *args, &block) : super
257
+ end
258
+ end
259
+ mydelegator = mydelegatorclass.new(@myclass)
260
+
261
+ assert_equal [1,2,[3]], mydelegator.myvalargs(1,2,3)
262
+ stub = MuchStub::Stub.new(mydelegator, :myvalargs){ |*args| args.inspect }
263
+ assert_equal '[1, 2, 3]', mydelegator.myvalargs(1,2,3)
264
+ assert_equal '[4, 5, 6]', mydelegator.myvalargs(4,5,6)
265
+ stub.with(4,5,6){ 'four-five-six' }
266
+ assert_equal 'four-five-six', mydelegator.myvalargs(4,5,6)
267
+ end
268
+
269
+ should "call to the original method" do
270
+ subject.teardown
271
+
272
+ # no args
273
+ stub = MuchStub::Stub.new(@myobj, :mymeth){ 'mymeth' }
274
+ assert_equal 'mymeth', stub.call([])
275
+ assert_equal 'meth', stub.call_method([])
276
+
277
+ # static args
278
+ stub = MuchStub::Stub.new(@myobj, :myval){ |val| val.to_s }
279
+ assert_equal '1', stub.call([1])
280
+ assert_equal 1, stub.call_method([1])
281
+ assert_equal '2', stub.call([2])
282
+ assert_equal 2, stub.call_method([2])
283
+ stub.with(2){ 'two' }
284
+ assert_equal 'two', stub.call([2])
285
+ assert_equal 2, stub.call_method([2])
286
+
287
+ # dynamic args
288
+ stub = MuchStub::Stub.new(@myobj, :myargs){ |*args| args.join(',') }
289
+ assert_equal '1,2', stub.call([1,2])
290
+ assert_equal [1,2], stub.call_method([1,2])
291
+ assert_equal '3,4,5', stub.call([3,4,5])
292
+ assert_equal [3,4,5], stub.call_method([3,4,5])
293
+ stub.with(3,4,5){ 'three-four-five' }
294
+ assert_equal 'three-four-five', stub.call([3,4,5])
295
+ assert_equal [3,4,5], stub.call_method([3,4,5])
296
+
297
+ # mixed static/dynamic args
298
+ stub = MuchStub::Stub.new(@myobj, :myvalargs){ |*args| args.join(',') }
299
+ assert_equal '1,2,3', stub.call([1,2,3])
300
+ assert_equal [1,2, [3]], stub.call_method([1,2,3])
301
+ assert_equal '3,4,5', stub.call([3,4,5])
302
+ assert_equal [3,4,[5]], stub.call_method([3,4,5])
303
+ stub.with(3,4,5){ 'three-four-five' }
304
+ assert_equal 'three-four-five', stub.call([3,4,5])
305
+ assert_equal [3,4,[5]], stub.call_method([3,4,5])
306
+
307
+ # blocks
308
+ blkcalled = false
309
+ blk = proc{ blkcalled = true }
310
+ stub = MuchStub::Stub.new(@myobj, :myblk){ blkcalled = 'true' }
311
+ stub.call([], &blk)
312
+ assert_equal 'true', blkcalled
313
+ stub.call_method([], &blk)
314
+ assert_equal true, blkcalled
315
+ end
316
+
317
+ should "store and remove itself on asserts main module" do
318
+ assert_equal subject, MuchStub.instance_variable_get(subject.ivar_name)
319
+ subject.teardown
320
+ assert_nil MuchStub.instance_variable_get(subject.ivar_name)
321
+ end
322
+
323
+ should "be removable" do
324
+ assert_equal 1, @myobj.myval(1)
325
+ stub = MuchStub::Stub.new(@myobj, :myval){ |val| val.to_s }
326
+ assert_equal '1', @myobj.myval(1)
327
+ stub.teardown
328
+ assert_equal 1, @myobj.myval(1)
329
+ end
330
+
331
+ should "have a readable inspect" do
332
+ expected = "#<#{subject.class}:#{'0x0%x' % (subject.object_id << 1)}" \
333
+ " @method_name=#{subject.method_name.inspect}>"
334
+ assert_equal expected, subject.inspect
335
+ end
336
+
337
+ end
338
+
339
+ class MutatingArgsStubTests < StubTests
340
+ desc "with args that are mutated after they've been used to stub"
341
+ setup do
342
+ @arg = ChangeHashObject.new
343
+
344
+ @stub = MuchStub::Stub.new(@myobj, :myval)
345
+ @stub.with(@arg){ true }
346
+
347
+ @arg.change!
348
+ end
349
+ subject{ @stub }
350
+
351
+ should "not raise a stub error when called" do
352
+ assert_nothing_raised{ @stub.call([@arg]) }
353
+ end
354
+
355
+ end
356
+
357
+ class StubInheritedMethodAfterStubbedOnParentTests < StubTests
358
+ desc "stubbing an inherited method after its stubbed on the parent class"
359
+ setup do
360
+ @parent_class = Class.new
361
+ @child_class = Class.new(@parent_class)
362
+
363
+ @parent_stub = MuchStub::Stub.new(@parent_class, :new)
364
+ @child_stub = MuchStub::Stub.new(@child_class, :new)
365
+ end
366
+
367
+ should "allow stubbing them independently of each other" do
368
+ assert_nothing_raised do
369
+ @parent_stub.with(1, 2){ 'parent' }
370
+ @child_stub.with(1, 2){ 'child' }
371
+ end
372
+ assert_equal 'parent', @parent_class.new(1, 2)
373
+ assert_equal 'child', @child_class.new(1, 2)
374
+ end
375
+
376
+ should "not raise any errors when tearing down the parent before the child" do
377
+ assert_nothing_raised do
378
+ @parent_stub.teardown
379
+ @child_stub.teardown
380
+ end
381
+ end
382
+
383
+ end
384
+
385
+ class NullStubTests < UnitTests
386
+ desc "NullStub"
387
+ setup do
388
+ @ns = NullStub.new
389
+ end
390
+ subject{ @ns }
391
+
392
+ should have_imeths :teardown
393
+
394
+ end
395
+
396
+ class ParameterListTests < UnitTests
397
+ desc "ParameterList"
398
+ setup do
399
+ many_args = (0..ParameterList::LETTERS.size).map do
400
+ Assert::Factory.string
401
+ end.join(', ')
402
+ @object = Class.new
403
+ # use `class_eval` with string to easily define methods with many params
404
+ @object.class_eval <<-methods
405
+ def self.noargs; end
406
+ def self.anyargs(*args); end
407
+ def self.manyargs(#{many_args}); end
408
+ def self.minargs(#{many_args}, *args); end
409
+ methods
410
+ end
411
+ subject{ ParameterList }
412
+
413
+ should "build a parameter list for a method that takes no args" do
414
+ assert_equal '&block', subject.new(@object, 'noargs')
415
+ end
416
+
417
+ should "build a parameter list for a method that takes any args" do
418
+ assert_equal '*args, &block', subject.new(@object, 'anyargs')
419
+ end
420
+
421
+ should "build a parameter list for a method that takes many args" do
422
+ expected = "#{ParameterList::LETTERS.join(', ')}, aa, &block"
423
+ assert_equal expected, subject.new(@object, 'manyargs')
424
+ end
425
+
426
+ should "build a parameter list for a method that takes a minimum number of args" do
427
+ expected = "#{ParameterList::LETTERS.join(', ')}, aa, *args, &block"
428
+ assert_equal expected, subject.new(@object, 'minargs')
429
+ end
430
+
431
+ end
432
+
433
+ class ChangeHashObject
434
+ def initialize
435
+ @value = nil
436
+ end
437
+
438
+ def hash
439
+ @value.hash
440
+ end
441
+
442
+ def change!
443
+ @value = 1
444
+ end
445
+ end
446
+
447
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: much-stub
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kelly Redding
8
+ - Collin Redding
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2018-06-05 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: assert
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: 2.16.3
23
+ type: :development
24
+ version_requirements: *id001
25
+ description: Stubbing API for replacing method calls on objects in test runs.
26
+ email:
27
+ - kelly@kellyredding.com
28
+ - collin.redding@me.com
29
+ executables: []
30
+
31
+ extensions: []
32
+
33
+ extra_rdoc_files: []
34
+
35
+ files:
36
+ - .gitignore
37
+ - Gemfile
38
+ - LICENSE
39
+ - README.md
40
+ - lib/much-stub.rb
41
+ - lib/much-stub/version.rb
42
+ - log/.gitkeep
43
+ - much-stub.gemspec
44
+ - test/helper.rb
45
+ - test/support/factory.rb
46
+ - test/system/much-stub_tests.rb
47
+ - test/unit/much-stub_tests.rb
48
+ - tmp/.gitkeep
49
+ homepage: https://github.com/redding/much-stub
50
+ licenses:
51
+ - MIT
52
+ metadata: {}
53
+
54
+ post_install_message:
55
+ rdoc_options: []
56
+
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - &id002
62
+ - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - *id002
68
+ requirements: []
69
+
70
+ rubyforge_project:
71
+ rubygems_version: 2.6.6
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: Stubbing API for replacing method calls on objects in test runs.
75
+ test_files:
76
+ - test/helper.rb
77
+ - test/support/factory.rb
78
+ - test/system/much-stub_tests.rb
79
+ - test/unit/much-stub_tests.rb