hardmock 1.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,371 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+ require 'hardmock'
3
+ class HardmockTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def teardown
9
+ end
10
+
11
+ #
12
+ # HELPERS
13
+ #
14
+
15
+ def assert_mock_exists(name)
16
+ assert_not_nil @all_mocks, "@all_mocks not here yet"
17
+ mo = @all_mocks[name]
18
+ assert_not_nil mo, "Mock '#{name}' not in @all_mocks"
19
+ assert_kind_of Mock, mo, "Wrong type of object, wanted a Mock"
20
+ assert_equal name.to_s, mo._name, "Mock '#{name}' had wrong name"
21
+ ivar = self.instance_variable_get("@#{name}")
22
+ assert_not_nil ivar, "Mock '#{name}' not set as ivar"
23
+ assert_same mo, ivar, "Mock '#{name}' ivar not same as instance in @all_mocks"
24
+ assert_same @main_mock_control, mo._control, "Mock '#{name}' doesn't share the main mock control"
25
+ end
26
+
27
+ #
28
+ # TESTS
29
+ #
30
+
31
+ def test_create_mock_and_create_mocks
32
+ assert_nil @main_mock_control, "@main_mock_control not expected yet"
33
+
34
+ h = create_mock :donkey
35
+ assert_equal [ :donkey ], h.keys
36
+ assert_not_nil @main_mock_control, "@main_mock_control should be here"
37
+
38
+ assert_mock_exists :donkey
39
+ assert_same @donkey, h[:donkey]
40
+
41
+ assert_equal [ :donkey ], @all_mocks.keys, "Wrong keyset for @all_mocks"
42
+
43
+ h2 = create_mocks :cat, 'dog' # symbol/string indifference at this level
44
+ assert_equal [:cat,:dog].to_set, h2.keys.to_set, "Wrong keyset for second hash"
45
+ assert_equal [:cat,:dog,:donkey].to_set, @all_mocks.keys.to_set, "@all_mocks wrong"
46
+
47
+ assert_mock_exists :cat
48
+ assert_same @cat, h2[:cat]
49
+ assert_mock_exists :dog
50
+ assert_same @dog, h2[:dog]
51
+
52
+ assert_mock_exists :donkey
53
+ end
54
+
55
+ def test_expect
56
+ assert_nil @order, "Should be no @order yet"
57
+ create_mock :order
58
+ assert_not_nil @order, "@order should be built"
59
+
60
+ # Setup an expectation
61
+ @order.expects.update_stuff :key1 => 'val1', :key2 => 'val2'
62
+
63
+ # Use the mock
64
+ @order.update_stuff :key1 => 'val1', :key2 => 'val2'
65
+
66
+ # Verify
67
+ verify_mocks
68
+
69
+ # See that it's ok to do it again
70
+ verify_mocks
71
+ end
72
+
73
+ def test_typical_multi_mock_use
74
+ create_mocks :order_builder, :order, :customer
75
+
76
+ @order_builder.expects.create_new_order.returns @order
77
+ @customer.expects.account_number.returns(1234)
78
+ @order.expects.account_no = 1234
79
+ @order.expects.save!
80
+
81
+ # Run "the code"
82
+ o = @order_builder.create_new_order
83
+ o.account_no = @customer.account_number
84
+ o.save!
85
+
86
+ verify_mocks
87
+ end
88
+
89
+ def test_typical_multi_mock_use_out_of_order
90
+ create_mocks :order_builder, :order, :customer
91
+
92
+ @order_builder.expects.create_new_order.returns @order
93
+ @customer.expects.account_number.returns(1234)
94
+ @order.expects.account_no = 1234
95
+ @order.expects.save!
96
+
97
+ # Run "the code"
98
+ o = @order_builder.create_new_order
99
+ err = assert_raise ExpectationError do
100
+ o.save!
101
+ end
102
+ assert_match(/wrong object/i, err.message)
103
+ assert_match(/order.save!/i, err.message)
104
+ assert_match(/customer.account_number/i, err.message)
105
+
106
+ assert_error VerifyError, /unmet expectations/i do
107
+ verify_mocks
108
+ end
109
+
110
+ # Appease the verifier
111
+ @order.account_no = 1234
112
+ @order.save!
113
+ end
114
+
115
+ class UserPresenter
116
+ def initialize(args)
117
+ view = args[:view]
118
+ model = args[:model]
119
+ model.when :data_changes do
120
+ view.user_name = model.user_name
121
+ end
122
+ view.when :user_edited do
123
+ model.user_name = view.user_name
124
+ end
125
+ end
126
+ end
127
+
128
+ def test_mvp_usage_pattern
129
+ mox = create_mocks :model, :view
130
+
131
+ data_change = @model.expects.when(:data_changes) { |evt,block| block }
132
+ user_edit = @view.expects.when(:user_edited) { |evt,block| block }
133
+
134
+ UserPresenter.new mox
135
+
136
+ # Expect user name transfer from model to view
137
+ @model.expects.user_name.returns 'Da Croz'
138
+ @view.expects.user_name = 'Da Croz'
139
+ # Trigger data change event in model
140
+ data_change.block_value.call
141
+
142
+ # Expect user name transfer from view to model
143
+ @view.expects.user_name.returns '6:8'
144
+ @model.expects.user_name = '6:8'
145
+ # Trigger edit event in view
146
+ user_edit.block_value.call
147
+
148
+ verify_mocks
149
+ end
150
+
151
+ def test_verify_mocks_repeated_anger
152
+ mox = create_mocks :model, :view
153
+ data_change = @model.expects.when(:data_changes) { |evt,block| block }
154
+ user_edit = @view.expects.when(:user_edited) { |evt,block| block }
155
+ UserPresenter.new mox
156
+
157
+ # Expect user name transfer from model to view
158
+ @model.expects.user_name.returns 'Da Croz'
159
+ @view.expects.user_name = 'Da Croz'
160
+
161
+ assert_error ExpectationError, /model.monkey_wrench/i do
162
+ @model.monkey_wrench
163
+ end
164
+
165
+ # This should raise because of unmet expectations
166
+ assert_error VerifyError, /unmet expectations/i, /user_name/i do
167
+ verify_mocks
168
+ end
169
+
170
+ # See that the non-forced verification remains quiet
171
+ assert_nothing_raised VerifyError do
172
+ verify_mocks(false)
173
+ end
174
+
175
+ # Finish meeting expectations and see good verification behavior
176
+ @view.user_name = "Da Croz"
177
+ verify_mocks
178
+
179
+ @model.expects.never_gonna_happen
180
+
181
+ assert_error VerifyError, /unmet expectations/i, /never_gonna_happen/i do
182
+ verify_mocks
183
+ end
184
+
185
+ # Appease the verifier
186
+ @model.never_gonna_happen
187
+ end
188
+
189
+ class UserPresenterBroken
190
+ def initialize(args)
191
+ view = args[:view]
192
+ model = args[:model]
193
+ model.when :data_changes do
194
+ view.user_name = model.user_name
195
+ end
196
+ # no view stuff, will break appropriately
197
+ end
198
+ end
199
+
200
+ def test_mvp_usage_with_failures_in_constructor
201
+ mox = create_mocks :model, :view
202
+
203
+ data_change = @model.expects.when(:data_changes) { |evt,block| block }
204
+ user_edit = @view.expects.when(:user_edited) { |evt,block| block }
205
+
206
+ UserPresenterBroken.new mox
207
+
208
+ err = assert_raise VerifyError do
209
+ verify_mocks
210
+ end
211
+ assert_match(/unmet expectations/i, err.message)
212
+ assert_match(/view.when\(:user_edited\)/i, err.message)
213
+
214
+ assert_error VerifyError, /unmet expectations/i do
215
+ verify_mocks
216
+ end
217
+
218
+ # Appease the verifier
219
+ @view.when(:user_edited)
220
+
221
+ end
222
+
223
+ def test_mvp_usage_pattern_with_convenience_trap
224
+ mox = create_mocks :model, :view
225
+
226
+ data_change = @model.trap.when(:data_changes)
227
+ user_edit = @view.trap.when(:user_edited)
228
+
229
+ UserPresenter.new mox
230
+
231
+ # Expect user name transfer from model to view
232
+ @model.expects.user_name.returns 'Da Croz'
233
+ @view.expects.user_name = 'Da Croz'
234
+ # Trigger data change event in model
235
+ data_change.trigger
236
+
237
+ # Expect user name transfer from view to model
238
+ @view.expects.user_name.returns '6:8'
239
+ @model.expects.user_name = '6:8'
240
+ # Trigger edit event in view
241
+ user_edit.trigger
242
+
243
+ verify_mocks
244
+ end
245
+
246
+ class Grinder
247
+ def initialize(objects)
248
+ @chute = objects[:chute]
249
+ @bucket = objects[:bucket]
250
+ @blade = objects[:blade]
251
+ end
252
+
253
+ def grind(slot)
254
+ @chute.each_bean(slot) do |bean|
255
+ @bucket << @blade.chop(bean)
256
+ end
257
+ end
258
+ end
259
+
260
+ def test_internal_iteration_usage
261
+ grinder = Grinder.new create_mocks(:blade, :chute, :bucket)
262
+
263
+ # Style 1: assertions on method args is done explicitly in block
264
+ @chute.expects.each_bean { |slot,block|
265
+ assert_equal :side_slot, slot, "Wrong slot"
266
+ block.call :bean1
267
+ block.call :bean2
268
+ }
269
+
270
+ @blade.expects.chop(:bean1).returns(:grounds1)
271
+ @bucket.expects('<<', :grounds1)
272
+
273
+ @blade.expects.chop(:bean2).returns(:grounds2)
274
+ @bucket.expects('<<', :grounds2)
275
+
276
+ # Run "the code"
277
+ grinder.grind(:side_slot)
278
+
279
+ verify_mocks
280
+
281
+ # Style 2: assertions on method arguments done implicitly in the expectation code
282
+ @chute.expects.each_bean(:main_slot) { |slot,block|
283
+ block.call :bean3
284
+ }
285
+ @blade.expects.chop(:bean3).returns(:grounds3)
286
+ @bucket.expects('<<', :grounds3)
287
+ grinder.grind :main_slot
288
+ verify_mocks
289
+ end
290
+
291
+ def test_internal_iteration_using_yield
292
+ grinder = Grinder.new create_mocks(:blade, :chute, :bucket)
293
+
294
+ @chute.expects.each_bean(:side_slot).yields :bean1, :bean2
295
+
296
+ @blade.expects.chop(:bean1).returns(:grounds1)
297
+ @bucket.expects('<<', :grounds1)
298
+
299
+ @blade.expects.chop(:bean2).returns(:grounds2)
300
+ @bucket.expects('<<', :grounds2)
301
+
302
+ grinder.grind :side_slot
303
+
304
+ verify_mocks
305
+ end
306
+
307
+ class HurtLocker
308
+ attr_reader :caught
309
+ def initialize(opts)
310
+ @locker = opts[:locker]
311
+ @store = opts[:store]
312
+ end
313
+
314
+ def do_the_thing(area,data)
315
+ @locker.with_lock(area) do
316
+ @store.eat(data)
317
+ end
318
+ rescue => oops
319
+ @caught = oops
320
+ end
321
+ end
322
+
323
+ def test_internal_locking_scenario
324
+ hurt = HurtLocker.new create_mocks(:locker, :store)
325
+
326
+ @locker.expects.with_lock(:main).yields
327
+ @store.expects.eat("some info")
328
+
329
+ hurt.do_the_thing(:main, "some info")
330
+
331
+ verify_mocks
332
+ end
333
+
334
+ def test_internal_locking_scenario_with_inner_error
335
+ hurt = HurtLocker.new create_mocks(:locker, :store)
336
+ err = StandardError.new('fmshooop')
337
+ @locker.expects.with_lock(:main).yields
338
+ @store.expects.eat("some info").raises(err)
339
+
340
+ hurt.do_the_thing(:main, "some info")
341
+
342
+ assert_same err, hurt.caught, "Expected that error to be handled internally"
343
+ verify_mocks
344
+ end
345
+
346
+ def test_returning_false_actually_returns_false_and_not_nil
347
+ create_mock :car
348
+ @car.expects.ignition_on?.returns(true)
349
+ assert_equal true, @car.ignition_on?, "Should be true"
350
+ @car.expects.ignition_on?.returns(false)
351
+ assert_equal false, @car.ignition_on?, "Should be false"
352
+ end
353
+
354
+ def test_should_raise_deprecation_error_when_old_expect_called
355
+ create_mock :foo
356
+ assert_error Hardmock::DeprecationError, /expect/,/expects/,/instead of/,/sorry/i do
357
+ @foo.expect.something
358
+ end
359
+ end
360
+
361
+ def test_should_be_able_to_mock_methods_inherited_from_object
362
+ target_methods = %w|to_s inspect instance_eval instance_variables id clone display dup eql? ==|
363
+ create_mock :foo
364
+ target_methods.each do |m|
365
+ eval %{@foo.expects(m, "some stuff")}
366
+ eval %{@foo.#{m} "some stuff"}
367
+ end
368
+ end
369
+
370
+ end
371
+
@@ -0,0 +1,23 @@
1
+ here = File.expand_path(File.dirname(__FILE__))
2
+ $: << here
3
+
4
+ require "#{here}/../config/environment"
5
+ require 'test/unit'
6
+ require 'fileutils'
7
+ require 'logger'
8
+ require 'find'
9
+ require 'yaml'
10
+ require 'set'
11
+ require 'ostruct'
12
+
13
+ class Test::Unit::TestCase
14
+ include FileUtils
15
+
16
+ def poll(time_limit)
17
+ (time_limit * 10).to_i.times do
18
+ return true if yield
19
+ sleep 0.1
20
+ end
21
+ return false
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+ require 'hardmock'
3
+
4
+ class ExpectationBuilderTest < Test::Unit::TestCase
5
+
6
+ def test_build_expectation
7
+ builder = ExpectationBuilder.new
8
+
9
+ ex = builder.build_expectation( :stuff => 'inside' )
10
+ assert_not_nil ex, "Didn't build an expectation"
11
+ assert_kind_of SimpleExpectation, ex, "Wrong type!"
12
+
13
+ # Shhhh... fragile, yes, whatever. The functional tests do the
14
+ # real testing of this anyway
15
+ assert_equal({:stuff => 'inside'}, ex.instance_variable_get('@options'), "Hash not sent to SimpleExpectation constructor")
16
+ end
17
+
18
+ end
@@ -0,0 +1,54 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+ require 'hardmock'
3
+
4
+ class ExpectorTest < Test::Unit::TestCase
5
+
6
+ class MyControl
7
+ attr_reader :added
8
+ def add_expectation(expectation)
9
+ @added ||= []
10
+ @added << expectation
11
+ end
12
+ end
13
+
14
+ class ExpBuilder
15
+ attr_reader :options
16
+ def build_expectation(options)
17
+ @options = options
18
+ "dummy expectation"
19
+ end
20
+ end
21
+
22
+ #
23
+ # TESTS
24
+ #
25
+
26
+ def test_method_missing
27
+ try_it_with 'wonder_bread'
28
+ try_it_with 'whatever'
29
+ end
30
+
31
+ def test_methods_that_wont_trigger_method_missing
32
+ try_it_with 'instance_eval'
33
+ end
34
+
35
+ def try_it_with(method_name)
36
+ mock = Object.new
37
+ mock_control = MyControl.new
38
+ builder = ExpBuilder.new
39
+
40
+ exp = Expector.new(mock, mock_control, builder)
41
+ output = exp.send(method_name,:with, 1, 'sauce')
42
+
43
+ assert_same mock, builder.options[:mock]
44
+ assert_equal method_name, builder.options[:method].to_s
45
+ assert_equal [:with,1,'sauce'], builder.options[:arguments]
46
+ assert_nil builder.options[:block]
47
+ assert_equal [ "dummy expectation" ], mock_control.added,
48
+ "Wrong expectation added to control"
49
+
50
+ assert_equal "dummy expectation", output, "Expectation should have been returned"
51
+ end
52
+
53
+
54
+ end
@@ -0,0 +1,35 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+ require 'method_cleanout'
3
+
4
+ class MethodCleanoutTest < Test::Unit::TestCase
5
+ class Victim
6
+ OriginalMethods = instance_methods
7
+ include Hardmock::MethodCleanout
8
+ end
9
+
10
+ def setup
11
+ @victim = Victim.new
12
+ end
13
+
14
+ def test_should_remove_most_methods_from_a_class
15
+ expect_removed = Victim::OriginalMethods.reject { |m|
16
+ Hardmock::MethodCleanout::SACRED_METHODS.include?(m)
17
+ }
18
+ expect_removed.each do |m|
19
+ assert !@victim.respond_to?(m), "should not have method #{m}"
20
+ end
21
+ end
22
+
23
+ def test_should_leave_the_sacred_methods_defined
24
+ Hardmock::MethodCleanout::SACRED_METHODS.each do |m|
25
+ assert @victim.respond_to?(m)
26
+ end
27
+ end
28
+
29
+ def test_should_include_certain_important_methods_in_the_sacred_methods_list
30
+ %w|__id__ __send__ send equal? respond_to? nil?|.each do |m|
31
+ assert Hardmock::MethodCleanout::SACRED_METHODS.include?(m), "important method #{m} is not included in SACRED_METHODS"
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,172 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+ require 'hardmock'
3
+
4
+ class MockControlTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @unmock = OpenStruct.new( :_name => 'fakemock' )
8
+
9
+ @control = MockControl.new
10
+ assert @control.happy?, "Control should start out happy"
11
+ end
12
+
13
+ def teardown
14
+ end
15
+
16
+ #
17
+ # HELPERS
18
+ #
19
+
20
+ class MyExp
21
+ attr_reader :mock, :mname, :args, :block
22
+ def apply_method_call(mock, mname, args, block)
23
+ @mock = mock
24
+ @mname = mname
25
+ @args = args
26
+ @block = block
27
+ end
28
+ end
29
+
30
+ class BoomExp < MyExp
31
+ def apply_method_call(mock, mname, args, block)
32
+ super
33
+ raise "BOOM"
34
+ end
35
+ end
36
+
37
+ #
38
+ # TESTS
39
+ #
40
+
41
+ def test_add_exepectation_and_apply_method_call
42
+ e1 = MyExp.new
43
+
44
+ @control.add_expectation e1
45
+ assert !@control.happy?
46
+
47
+ @control.apply_method_call @unmock, 'some_func', [ 'the', :args ], nil
48
+ assert @control.happy?
49
+
50
+ assert_same @unmock, e1.mock, "Wrong mock"
51
+ assert_equal 'some_func', e1.mname, "Wrong method"
52
+ assert_equal [ 'the', :args ], e1.args, "Wrong args"
53
+
54
+ @control.verify
55
+ end
56
+
57
+ def test_add_exepectation_and_apply_method_call_with_block
58
+ e1 = MyExp.new
59
+
60
+ @control.add_expectation e1
61
+ assert !@control.happy?
62
+
63
+ runtime_block = Proc.new { "hello" }
64
+ @control.apply_method_call @unmock, 'some_func', [ 'the', :args ], runtime_block
65
+ assert @control.happy?
66
+
67
+ assert_same @unmock, e1.mock, "Wrong mock"
68
+ assert_equal 'some_func', e1.mname, "Wrong method"
69
+ assert_equal [ 'the', :args ], e1.args, "Wrong args"
70
+ assert_equal "hello", e1.block.call, "Wrong block in expectation"
71
+
72
+ @control.verify
73
+ end
74
+
75
+ def test_add_expectation_then_verify
76
+ e1 = MyExp.new
77
+
78
+ @control.add_expectation e1
79
+ assert !@control.happy?, "Shoudn't be happy"
80
+ err = assert_raise VerifyError do
81
+ @control.verify
82
+ end
83
+ assert_match(/unmet expectations/i, err.message)
84
+
85
+ @control.apply_method_call @unmock, 'some_func', [ 'the', :args ], nil
86
+ assert @control.happy?
87
+
88
+ assert_same @unmock, e1.mock, "Wrong mock"
89
+ assert_equal 'some_func', e1.mname, "Wrong method"
90
+ assert_equal [ 'the', :args ], e1.args, "Wrong args"
91
+
92
+ @control.verify
93
+ end
94
+
95
+ def test_expectation_explosion
96
+ be1 = BoomExp.new
97
+
98
+ @control.add_expectation be1
99
+
100
+ err = assert_raise RuntimeError do
101
+ @control.apply_method_call @unmock, 'a func', [:arg], nil
102
+ end
103
+ assert_match(/BOOM/i, err.message)
104
+
105
+ assert_same @unmock, be1.mock
106
+ assert_equal 'a func', be1.mname
107
+ assert_equal [:arg], be1.args
108
+ end
109
+
110
+ def test_disappointment_on_bad_verify
111
+ @control.add_expectation MyExp.new
112
+ assert !@control.happy?, "Shouldn't be happy"
113
+ assert !@control.disappointed?, "too early to be disappointed"
114
+
115
+ # See verify fails
116
+ err = assert_raise VerifyError do
117
+ @control.verify
118
+ end
119
+ assert_match(/unmet expectations/i, err.message)
120
+
121
+ assert !@control.happy?, "Still have unmet expectation"
122
+ assert @control.disappointed?, "We should be disappointed following that failure"
123
+
124
+ @control.apply_method_call @unmock, 'something', [], nil
125
+ assert @control.happy?, "Should be happy"
126
+ assert @control.disappointed?, "We should be skeptical"
127
+
128
+ @control.verify
129
+
130
+ assert !@control.disappointed?, "Should be non-disappointed"
131
+ end
132
+
133
+ def test_disappointment_from_surprise_calls
134
+ assert @control.happy?, "Should be happy"
135
+ assert !@control.disappointed?, "too early to be disappointed"
136
+
137
+ # See verify fails
138
+ err = assert_raise ExpectationError do
139
+ @control.apply_method_call @unmock, "something", [], nil
140
+ end
141
+ assert_match(/surprise/i, err.message)
142
+
143
+ assert @control.happy?, "Happiness is an empty list of expectations"
144
+ assert @control.disappointed?, "We should be disappointed following that failure"
145
+
146
+ @control.verify
147
+ assert !@control.disappointed?, "Disappointment should be gone"
148
+ end
149
+
150
+ def test_disappointment_from_bad_calls
151
+ be1 = BoomExp.new
152
+ assert !@control.disappointed?, "Shouldn't be disappointed"
153
+ @control.add_expectation be1
154
+ assert !@control.disappointed?, "Shouldn't be disappointed"
155
+
156
+ err = assert_raise RuntimeError do
157
+ @control.apply_method_call @unmock, 'a func', [:arg], nil
158
+ end
159
+ assert_match(/BOOM/i, err.message)
160
+ assert @control.disappointed?, "Should be disappointed"
161
+
162
+ assert_same @unmock, be1.mock
163
+ assert_equal 'a func', be1.mname
164
+ assert_equal [:arg], be1.args
165
+
166
+ assert @control.happy?, "Happiness is an empty list of expectations"
167
+ @control.verify
168
+ assert !@control.disappointed?, "Disappointment should be gone"
169
+ end
170
+
171
+
172
+ end