hardmock 1.3.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rake'
2
2
  require 'rubygems'
3
3
 
4
- HARDMOCK_VERSION = "1.3.0"
4
+ HARDMOCK_VERSION = "1.3.1"
5
5
 
6
6
  Dir["lib/tasks/*.rake"].each { |f| load f }
7
7
 
data/lib/hardmock.rb CHANGED
@@ -15,6 +15,11 @@ module Hardmock
15
15
  # with inherited, pre-mixed or post-added user teardowns.
16
16
  def self.included(base) #:nodoc:#
17
17
  base.class_eval do
18
+ # Core of our actual setup behavior
19
+ def hardmock_setup
20
+ prepare_hardmock_control
21
+ end
22
+
18
23
  # Core of our actual teardown behavior
19
24
  def hardmock_teardown
20
25
  verify_mocks
@@ -24,6 +29,24 @@ module Hardmock
24
29
  def self.method_added(symbol) #:nodoc:
25
30
  end
26
31
 
32
+ if method_defined?(:setup) then
33
+ # Wrap existing setup
34
+ alias_method :old_setup, :setup
35
+ define_method(:new_setup) do
36
+ begin
37
+ hardmock_setup
38
+ ensure
39
+ old_setup
40
+ end
41
+ end
42
+ else
43
+ # We don't need to account for previous setup
44
+ define_method(:new_setup) do
45
+ hardmock_setup
46
+ end
47
+ end
48
+ alias_method :setup, :new_setup
49
+
27
50
  if method_defined?(:teardown) then
28
51
  # Wrap existing teardown
29
52
  alias_method :old_teardown, :teardown
@@ -55,6 +78,17 @@ module Hardmock
55
78
  end
56
79
  end
57
80
  end
81
+ when :setup
82
+ unless method_defined?(:user_setup)
83
+ alias_method :user_setup, :setup
84
+ define_method(:setup) do
85
+ begin
86
+ new_setup
87
+ ensure
88
+ user_setup
89
+ end
90
+ end
91
+ end
58
92
  end
59
93
  end
60
94
  end
@@ -113,26 +147,21 @@ module Hardmock
113
147
  @main_mock_control.verify
114
148
  ensure
115
149
  @main_mock_control.clear_expectations if @main_mock_control
116
- Hardmock.restore_all_stubbed_methods
117
150
  $main_mock_control = nil
151
+ reset_stubs
118
152
  end
119
153
 
120
154
  # Purge the main MockControl of all expectations, restore all concrete stubbed/mocked methods
121
155
  def clear_expectations
122
156
  @main_mock_control.clear_expectations if @main_mock_control
123
- Hardmock.restore_all_stubbed_methods
157
+ reset_stubs
124
158
  $main_mock_control = nil
125
159
  end
126
160
 
127
- # def self.set_main_mock_control(control)
128
- # $main_mock_control = control
129
- # end
161
+ def reset_stubs
162
+ Hardmock.restore_all_replaced_methods
163
+ end
130
164
 
131
- # def self.main_mock_control
132
- # raise "No main mock control set yet... chickening out" if $main_mock_control.nil?
133
- # $main_mock_control
134
- # end
135
-
136
165
  end
137
166
 
138
167
  # Insert Hardmock functionality into the TestCase base class
@@ -23,6 +23,10 @@ class Object #:nodoc:#
23
23
  meta_eval { define_method name, &blk }
24
24
  end
25
25
 
26
+ # def meta_eval_string(str)
27
+ # metaclass.instance_eval(str)
28
+ # end
29
+
26
30
  # Defines an instance method within a class
27
31
  # def class_def(name, &blk) #:nodoc:#
28
32
  # class_eval { define_method name, &blk }
@@ -59,47 +63,47 @@ module Hardmock
59
63
  # Exists only for documentation
60
64
  end
61
65
 
62
- class StubbedMethod #:nodoc:#
66
+ class ReplacedMethod
63
67
  attr_reader :target, :method_name
64
68
 
65
69
  def initialize(target, method_name)
66
70
  @target = target
67
71
  @method_name = method_name
68
72
 
69
- Hardmock.add_stubbed_method self
73
+ Hardmock.track_replaced_method self
70
74
  end
75
+ end
71
76
 
77
+ class StubbedMethod < ReplacedMethod #:nodoc:#
72
78
  def invoke(args)
79
+ raise @raises if @raises
73
80
  @return_value
74
81
  end
75
82
 
76
83
  def returns(stubbed_return)
77
84
  @return_value = stubbed_return
78
85
  end
79
- end
80
-
81
- class MockedMethod < StubbedMethod #:nodoc:#
82
-
83
- def initialize(target, method_name, mock)
84
- super target,method_name
85
- @mock = mock
86
- end
87
86
 
88
- def invoke(args)
89
- @mock.__send__(self.method_name.to_sym, *args)
87
+ def raises(err)
88
+ err = RuntimeError.new(err) unless err.kind_of?(Exception)
89
+ @raises = err
90
+ # puts "Setup to raise #{@raises}"
90
91
  end
91
-
92
92
  end
93
93
 
94
94
  class ::Object
95
95
  def stubs!(method_name)
96
96
  _ensure_stubbable method_name
97
-
98
97
  method_name = method_name.to_s
98
+ already_stubbed = Hardmock.has_replaced_method?(self, method_name)
99
+
99
100
  stubbed_method = Hardmock::StubbedMethod.new(self, method_name)
100
101
 
101
- meta_eval do
102
- alias_method "_hardmock_original_#{method_name}".to_sym, method_name.to_sym
102
+
103
+ unless _is_mock? or already_stubbed
104
+ meta_eval do
105
+ alias_method "_hardmock_original_#{method_name}".to_sym, method_name.to_sym
106
+ end
103
107
  end
104
108
 
105
109
  meta_def method_name do |*args|
@@ -110,26 +114,41 @@ module Hardmock
110
114
  end
111
115
 
112
116
  def expects!(method_name, *args, &block)
117
+ if self._is_mock?
118
+ raise Hardmock::StubbingError, "Cannot use 'expects!(:#{method_name})' on a Mock object; try 'expects' instead"
119
+ end
113
120
  _ensure_stubbable method_name
114
121
 
115
122
  method_name = method_name.to_s
116
123
 
117
124
  if @_my_mock.nil?
118
125
  @_my_mock = Mock.new(_my_name, $main_mock_control)
119
- stubbed_method = Hardmock::MockedMethod.new(self, method_name, @_my_mock)
126
+ Hardmock::ReplacedMethod.new(self, method_name)
127
+
120
128
  meta_eval do
121
129
  alias_method "_hardmock_original_#{method_name}".to_sym, method_name.to_sym
122
130
  end
123
- meta_def(method_name) do |*args|
124
- stubbed_method.invoke(args)
131
+
132
+ begin
133
+ $method_text_temp = %{
134
+ def #{method_name}(*args,&block)
135
+ @_my_mock.__send__(:#{method_name}, *args, &block)
136
+ end
137
+ }
138
+ class << self
139
+ eval $method_text_temp
140
+ end
141
+ ensure
142
+ $method_text_temp = nil
125
143
  end
144
+
126
145
  end
127
146
 
128
147
  return @_my_mock.expects(method_name, *args, &block)
129
148
  end
130
149
 
131
150
  def _ensure_stubbable(method_name)
132
- unless self.respond_to?(method_name.to_sym)
151
+ unless self.respond_to?(method_name.to_sym) or self._is_mock?
133
152
  msg = "Cannot stub non-existant "
134
153
  if self.kind_of?(Class)
135
154
  msg += "class method #{_my_name}."
@@ -141,6 +160,10 @@ module Hardmock
141
160
  end
142
161
  end
143
162
 
163
+ def _is_mock?
164
+ self.kind_of?(Mock)
165
+ end
166
+
144
167
  def _my_name
145
168
  self.kind_of?(Class) ? self.name : self.class.name
146
169
  end
@@ -152,21 +175,31 @@ module Hardmock
152
175
  end
153
176
 
154
177
  class << self
155
- def add_stubbed_method(stubbed_method)
156
- all_stubbed_methods << stubbed_method
178
+ def track_replaced_method(replaced_method)
179
+ all_replaced_methods << replaced_method
157
180
  end
158
181
 
159
- def all_stubbed_methods
160
- $all_stubbed_methods ||= []
182
+ def all_replaced_methods
183
+ $all_replaced_methods ||= []
184
+ end
185
+
186
+ def has_replaced_method?(obj, method_name)
187
+ hits = all_replaced_methods.select do |replaced|
188
+ (replaced.target.object_id == obj.object_id) and (replaced.method_name.to_s == method_name.to_s)
189
+ end
190
+ return !hits.empty?
161
191
  end
162
192
 
163
- def restore_all_stubbed_methods
164
- all_stubbed_methods.each do |sm|
165
- sm.target.meta_eval do
166
- alias_method sm.method_name.to_sym, "_hardmock_original_#{sm.method_name}".to_sym
193
+ def restore_all_replaced_methods
194
+ all_replaced_methods.each do |replaced|
195
+ unless replaced.target._is_mock?
196
+ replaced.target.meta_eval do
197
+ alias_method replaced.method_name.to_sym, "_hardmock_original_#{replaced.method_name}".to_sym
198
+ end
199
+ replaced.target._clear_mock
167
200
  end
168
- sm.target._clear_mock
169
201
  end
202
+ all_replaced_methods.clear
170
203
  end
171
204
  end
172
205
 
@@ -9,11 +9,9 @@ class HardmockTest < Test::Unit::TestCase
9
9
  #
10
10
 
11
11
  it "conveniently creates mocks using create_mock and create_mocks" do
12
- assert_nil @main_mock_control, "@main_mock_control not expected yet"
13
12
 
14
13
  h = create_mock :donkey
15
14
  assert_equal [ :donkey ], h.keys
16
- assert_not_nil @main_mock_control, "@main_mock_control should be here"
17
15
 
18
16
  assert_mock_exists :donkey
19
17
  assert_same @donkey, h[:donkey]
@@ -380,7 +378,7 @@ class HardmockTest < Test::Unit::TestCase
380
378
  assert_equal "<Mock hay_bailer>", @hay_bailer.inspect, "Wrong output from 'inspect'"
381
379
  end
382
380
 
383
- it "raises is prepare_hardmock_control is invoked after create_mocks, or more than once" do
381
+ it "raises if prepare_hardmock_control is invoked after create_mocks, or more than once" do
384
382
  create_mock :hi_there
385
383
  create_mocks :another, :one
386
384
  assert_error RuntimeError, /already setup/ do
@@ -8,7 +8,7 @@ class StubbingTest < Test::Unit::TestCase
8
8
  # TESTS
9
9
  #
10
10
 
11
- it "stubs a class method (and un-stubs after verify)" do
11
+ it "stubs a class method (and un-stubs after reset_stubs)" do
12
12
  assert_equal "stones and gravel", Concrete.pour
13
13
  assert_equal "glug glug", Jug.pour
14
14
 
@@ -23,7 +23,7 @@ class StubbingTest < Test::Unit::TestCase
23
23
 
24
24
  assert_equal "For roads", Concrete.describe, "'describe' method broken"
25
25
 
26
- verify_mocks
26
+ reset_stubs
27
27
 
28
28
  assert_equal "stones and gravel", Concrete.pour, "'pour' method not restored"
29
29
  assert_equal "For roads", Concrete.describe, "'describe' method broken after verify"
@@ -39,7 +39,7 @@ class StubbingTest < Test::Unit::TestCase
39
39
  assert_equal "awful", Concrete.describe
40
40
  assert_equal "milk", Jug.pour
41
41
 
42
- verify_mocks
42
+ reset_stubs
43
43
 
44
44
  assert_equal "stones and gravel", Concrete.pour
45
45
  assert_equal "For roads", Concrete.describe
@@ -53,7 +53,7 @@ class StubbingTest < Test::Unit::TestCase
53
53
  slab.stubs!(:hit).returns("slap")
54
54
  assert_equal "slap", slab.hit, "'hit' not stubbed"
55
55
 
56
- verify_mocks
56
+ reset_stubs
57
57
 
58
58
  assert_equal "bonk", slab.hit, "'hit' not restored"
59
59
  end
@@ -70,7 +70,7 @@ class StubbingTest < Test::Unit::TestCase
70
70
  assert_equal "an instance", scrape.describe, "'describe' on 'scrape' instance broken"
71
71
  assert_equal "For roads", Concrete.describe, "'describe' class method broken"
72
72
 
73
- verify_mocks
73
+ reset_stubs
74
74
 
75
75
  assert_equal "an instance", slab.describe, "'describe' instance method not restored"
76
76
  assert_equal "an instance", scrape.describe, "'describe' on 'scrape' instance broken after restore"
@@ -89,14 +89,47 @@ class StubbingTest < Test::Unit::TestCase
89
89
  end
90
90
  end
91
91
 
92
+ should "allow re-stubbing" do
93
+ Concrete.stubs!(:pour).returns("one")
94
+ assert_equal "one", Concrete.pour
95
+
96
+ Concrete.stubs!(:pour).raises("hell")
97
+ assert_error RuntimeError, /hell/ do
98
+ Concrete.pour
99
+ end
100
+
101
+ Concrete.stubs!(:pour).returns("two")
102
+ assert_equal "two", Concrete.pour
103
+
104
+ reset_stubs
105
+
106
+ assert_equal "stones and gravel", Concrete.pour
107
+ end
108
+
92
109
  it "does nothing with a runtime block when simply stubbing" do
93
- prepare_hardmock_control
110
+
94
111
  slab = Concrete.new
95
112
  slab.stubs!(:hit) do |nothing|
96
113
  raise "BOOOMM!"
97
114
  end
98
115
  slab.hit
99
- verify_mocks
116
+ reset_stubs
117
+ end
118
+
119
+ it "can raise errors from a stubbed method" do
120
+
121
+ Concrete.stubs!(:pour).raises(StandardError.new("no!"))
122
+ assert_error StandardError, /no!/ do
123
+ Concrete.pour
124
+ end
125
+ end
126
+
127
+ it "provides string syntax for convenient raising of RuntimeErrors" do
128
+
129
+ Concrete.stubs!(:pour).raises("never!")
130
+ assert_error RuntimeError, /never!/ do
131
+ Concrete.pour
132
+ end
100
133
  end
101
134
 
102
135
 
@@ -105,7 +138,7 @@ class StubbingTest < Test::Unit::TestCase
105
138
  #
106
139
 
107
140
  it "mocks specific methods on existing classes, and returns the class method to normal after verification" do
108
- prepare_hardmock_control
141
+
109
142
  assert_equal "stones and gravel", Concrete.pour, "Concrete.pour is already messed up"
110
143
 
111
144
  Concrete.expects!(:pour).returns("ALIGATORS")
@@ -116,7 +149,7 @@ class StubbingTest < Test::Unit::TestCase
116
149
  end
117
150
 
118
151
  it "flunks if expected class method is not invoked" do
119
- prepare_hardmock_control
152
+
120
153
  Concrete.expects!(:pour).returns("ALIGATORS")
121
154
  assert_error(Hardmock::VerifyError, /Concrete.pour/, /unmet expectations/i) do
122
155
  verify_mocks
@@ -125,7 +158,7 @@ class StubbingTest < Test::Unit::TestCase
125
158
  end
126
159
 
127
160
  it "supports all normal mock functionality for class methods" do
128
- prepare_hardmock_control
161
+
129
162
  Concrete.expects!(:pour, "two tons").returns("mice")
130
163
  Concrete.expects!(:pour, "three tons").returns("cats")
131
164
  Concrete.expects!(:pour, "four tons").raises("Can't do it")
@@ -160,14 +193,14 @@ class StubbingTest < Test::Unit::TestCase
160
193
  end
161
194
 
162
195
  should "not allow mocking non-existant class methods" do
163
- prepare_hardmock_control
196
+
164
197
  assert_error Hardmock::StubbingError, /non-existant/, /something/ do
165
198
  Concrete.expects!(:something)
166
199
  end
167
200
  end
168
201
 
169
202
  it "mocks specific methods on existing instances, then restore them after verify" do
170
- prepare_hardmock_control
203
+
171
204
  slab = Concrete.new
172
205
  assert_equal "bonk", slab.hit
173
206
 
@@ -179,7 +212,7 @@ class StubbingTest < Test::Unit::TestCase
179
212
  end
180
213
 
181
214
  it "flunks if expected instance method is not invoked" do
182
- prepare_hardmock_control
215
+
183
216
  slab = Concrete.new
184
217
  slab.expects!(:hit)
185
218
 
@@ -190,7 +223,7 @@ class StubbingTest < Test::Unit::TestCase
190
223
  end
191
224
 
192
225
  it "supports all normal mock functionality for instance methods" do
193
- prepare_hardmock_control
226
+
194
227
  slab = Concrete.new
195
228
 
196
229
  slab.expects!(:hit, "soft").returns("hey")
@@ -233,14 +266,50 @@ class StubbingTest < Test::Unit::TestCase
233
266
  end
234
267
 
235
268
  should "not allow mocking non-existant instance methods" do
236
- prepare_hardmock_control
269
+
237
270
  slab = Concrete.new
238
271
  assert_error Hardmock::StubbingError, /non-existant/, /something/ do
239
272
  slab.expects!(:something)
240
273
  end
241
274
  end
242
275
 
243
- should "support expectations that deal with runtime blocks"
276
+ should "support concrete expectations that deal with runtime blocks" do
277
+
278
+ Concrete.expects!(:pour, "a lot") do |how_much, block|
279
+ assert_equal "a lot", how_much, "Wrong how_much arg"
280
+ assert_not_nil block, "nil runtime block"
281
+ assert_equal "the block value", block.call, "Wrong runtime block value"
282
+ end
283
+
284
+ Concrete.pour("a lot") do
285
+ "the block value"
286
+ end
287
+
288
+ end
289
+
290
+ it "can stub methods on mock objects" do
291
+ create_mock :horse
292
+ @horse.stubs!(:speak).returns("silence")
293
+ @horse.stubs!(:hello).returns("nothing")
294
+ @horse.expects(:canter).returns("clip clop")
295
+
296
+ assert_equal "silence", @horse.speak
297
+ assert_equal "clip clop", @horse.canter
298
+ assert_equal "silence", @horse.speak
299
+ assert_equal "silence", @horse.speak
300
+ assert_equal "nothing", @horse.hello
301
+ assert_equal "nothing", @horse.hello
302
+
303
+ verify_mocks
304
+ reset_stubs
305
+ end
306
+
307
+ it "will not allow expects! to be used on a mock object" do
308
+ create_mock :cow
309
+ assert_error Hardmock::StubbingError, /expects!/, /mock/i, /something/ do
310
+ @cow.expects!(:something)
311
+ end
312
+ end
244
313
 
245
314
  #
246
315
  # HELPERS
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: hardmock
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.3.0
7
- date: 2007-11-12 00:00:00 -05:00
6
+ version: 1.3.1
7
+ date: 2007-11-17 00:00:00 -05:00
8
8
  summary: A strict, ordered, expectation-oriented mock object library.
9
9
  require_paths:
10
10
  - lib