hardmock 1.2.3 → 1.3.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.
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rake'
2
2
  require 'rubygems'
3
3
 
4
- HARDMOCK_VERSION = "1.2.3"
4
+ HARDMOCK_VERSION = "1.3.0"
5
5
 
6
6
  Dir["lib/tasks/*.rake"].each { |f| load f }
7
7
 
data/lib/assert_error.rb CHANGED
@@ -1,20 +1,22 @@
1
1
  require 'test/unit/assertions'
2
2
 
3
- module Test::Unit::Assertions
4
- # A better 'assert_raise'. +patterns+ can be one or more Regexps, or a literal String that
5
- # must match the entire error message.
6
- def assert_error(err_type,*patterns,&block)
7
- assert_not_nil block, "assert_error requires a block"
8
- assert((err_type and err_type.kind_of?(Class)), "First argument to assert_error has to be an error type")
9
- err = assert_raise(err_type) do
10
- block.call
11
- end
12
- patterns.each do |pattern|
13
- case pattern
14
- when Regexp
15
- assert_match(pattern, err.message)
16
- else
17
- assert_equal pattern, err.message
3
+ module Test::Unit #:nodoc:#
4
+ module Assertions #:nodoc:#
5
+ # A better 'assert_raise'. +patterns+ can be one or more Regexps, or a literal String that
6
+ # must match the entire error message.
7
+ def assert_error(err_type,*patterns,&block)
8
+ assert_not_nil block, "assert_error requires a block"
9
+ assert((err_type and err_type.kind_of?(Class)), "First argument to assert_error has to be an error type")
10
+ err = assert_raise(err_type) do
11
+ block.call
12
+ end
13
+ patterns.each do |pattern|
14
+ case pattern
15
+ when Regexp
16
+ assert_match(pattern, err.message)
17
+ else
18
+ assert_equal pattern, err.message
19
+ end
18
20
  end
19
21
  end
20
22
  end
@@ -7,6 +7,9 @@ module Hardmock
7
7
  # Raised for methods that should no longer be called. Hopefully, the exception message contains helpful alternatives.
8
8
  class DeprecationError < StandardError; end
9
9
 
10
+ # Raised when stubbing fails
11
+ class StubbingError < StandardError; end
12
+
10
13
  # Raised when it is discovered that an expected method call was never made.
11
14
  class VerifyError < StandardError
12
15
  def initialize(msg,unmet_expectations)
@@ -176,7 +176,7 @@ module Hardmock
176
176
  # Yield once
177
177
  @options[:block] = lambda do |block|
178
178
  if block.arity != 0 and block.arity != -1
179
- raise ExpectationError.new("Can't pass #{item.inspect} to block with arity #{block.arity} to <#{to_s}>")
179
+ raise ExpectationError.new("The given block was expected to have no parameter count; instead, got #{block.arity} to <#{to_s}>")
180
180
  end
181
181
  block.call
182
182
  end
@@ -6,8 +6,7 @@ module Hardmock
6
6
  attr_accessor :name
7
7
 
8
8
  def initialize
9
- @expectations = []
10
- @disappointed = false
9
+ clear_expectations
11
10
  end
12
11
 
13
12
  def happy?
@@ -19,6 +18,7 @@ module Hardmock
19
18
  end
20
19
 
21
20
  def add_expectation(expectation)
21
+ # puts "MockControl #{self.object_id.to_s(16)} adding expectation: #{expectation}"
22
22
  @expectations << expectation
23
23
  end
24
24
 
@@ -38,8 +38,16 @@ module Hardmock
38
38
  end
39
39
 
40
40
  def verify
41
+ # puts "MockControl #{self.object_id.to_s(16)} verify: happy? #{happy?}"
41
42
  @disappointed = !happy?
42
43
  raise VerifyError.new("Unmet expectations", @expectations) unless happy?
43
44
  end
45
+
46
+ def clear_expectations
47
+ @expectations = []
48
+ @disappointed = false
49
+ end
50
+
44
51
  end
52
+
45
53
  end
@@ -0,0 +1,174 @@
1
+ #
2
+ # Stubbing support
3
+ #
4
+ # Stubs methods on classes and instances
5
+ #
6
+
7
+ # Why's "metaid.rb":
8
+ class Object #:nodoc:#
9
+ # The hidden singleton lurks behind everyone
10
+ def metaclass #:nodoc:#
11
+ class << self
12
+ self
13
+ end
14
+ end
15
+
16
+ # Evaluate a block of code within the metaclass
17
+ def meta_eval(&blk) #:nodoc:#
18
+ metaclass.instance_eval(&blk)
19
+ end
20
+
21
+ # Adds methods to a metaclass
22
+ def meta_def(name, &blk) #:nodoc:#
23
+ meta_eval { define_method name, &blk }
24
+ end
25
+
26
+ # Defines an instance method within a class
27
+ # def class_def(name, &blk) #:nodoc:#
28
+ # class_eval { define_method name, &blk }
29
+ # end
30
+ end
31
+
32
+
33
+
34
+ module Hardmock
35
+
36
+ # == Hardmock: Stubbing and Mocking Concrete Methods
37
+ #
38
+ # Hardmock lets you stub and/or mock methods on concrete classes or objects.
39
+ #
40
+ # * To "stub" a concrete method is to rig it to return the same thing always, disregarding any arguments.
41
+ # * To "mock" a concrete method is to surplant its funcionality by delegating to a mock object who will cover this behavior.
42
+ #
43
+ # Mocked methods have their expectations considered along with all other mock object expectations.
44
+ #
45
+ # If you use stubbing or concrete mocking in the absence (or before creation) of other mocks, you need to invoke <tt>prepare_hardmock_control</tt>.
46
+ # Once <tt>verify_mocks</tt> or <tt>clear_expectaions</tt> is called, the overriden behavior in the target objects is restored.
47
+ #
48
+ # == Examples
49
+ #
50
+ # River.stubs!(:sounds_like).returns("gurgle")
51
+ #
52
+ # River.expects!(:jump).returns("splash")
53
+ #
54
+ # rogue.stubs!(:sounds_like).returns("pshshsh")
55
+ #
56
+ # rogue.expects!(:rawhide_tanning_solvents).returns("giant snapping turtles")
57
+ #
58
+ module Stubbing
59
+ # Exists only for documentation
60
+ end
61
+
62
+ class StubbedMethod #:nodoc:#
63
+ attr_reader :target, :method_name
64
+
65
+ def initialize(target, method_name)
66
+ @target = target
67
+ @method_name = method_name
68
+
69
+ Hardmock.add_stubbed_method self
70
+ end
71
+
72
+ def invoke(args)
73
+ @return_value
74
+ end
75
+
76
+ def returns(stubbed_return)
77
+ @return_value = stubbed_return
78
+ 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
+
88
+ def invoke(args)
89
+ @mock.__send__(self.method_name.to_sym, *args)
90
+ end
91
+
92
+ end
93
+
94
+ class ::Object
95
+ def stubs!(method_name)
96
+ _ensure_stubbable method_name
97
+
98
+ method_name = method_name.to_s
99
+ stubbed_method = Hardmock::StubbedMethod.new(self, method_name)
100
+
101
+ meta_eval do
102
+ alias_method "_hardmock_original_#{method_name}".to_sym, method_name.to_sym
103
+ end
104
+
105
+ meta_def method_name do |*args|
106
+ stubbed_method.invoke(args)
107
+ end
108
+
109
+ stubbed_method
110
+ end
111
+
112
+ def expects!(method_name, *args, &block)
113
+ _ensure_stubbable method_name
114
+
115
+ method_name = method_name.to_s
116
+
117
+ if @_my_mock.nil?
118
+ @_my_mock = Mock.new(_my_name, $main_mock_control)
119
+ stubbed_method = Hardmock::MockedMethod.new(self, method_name, @_my_mock)
120
+ meta_eval do
121
+ alias_method "_hardmock_original_#{method_name}".to_sym, method_name.to_sym
122
+ end
123
+ meta_def(method_name) do |*args|
124
+ stubbed_method.invoke(args)
125
+ end
126
+ end
127
+
128
+ return @_my_mock.expects(method_name, *args, &block)
129
+ end
130
+
131
+ def _ensure_stubbable(method_name)
132
+ unless self.respond_to?(method_name.to_sym)
133
+ msg = "Cannot stub non-existant "
134
+ if self.kind_of?(Class)
135
+ msg += "class method #{_my_name}."
136
+ else
137
+ msg += "method #{_my_name}#"
138
+ end
139
+ msg += method_name.to_s
140
+ raise Hardmock::StubbingError.new(msg)
141
+ end
142
+ end
143
+
144
+ def _my_name
145
+ self.kind_of?(Class) ? self.name : self.class.name
146
+ end
147
+
148
+ def _clear_mock
149
+ @_my_mock = nil
150
+ end
151
+
152
+ end
153
+
154
+ class << self
155
+ def add_stubbed_method(stubbed_method)
156
+ all_stubbed_methods << stubbed_method
157
+ end
158
+
159
+ def all_stubbed_methods
160
+ $all_stubbed_methods ||= []
161
+ end
162
+
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
167
+ end
168
+ sm.target._clear_mock
169
+ end
170
+ end
171
+ end
172
+
173
+ end
174
+
data/lib/hardmock.rb CHANGED
@@ -7,6 +7,7 @@ require 'hardmock/trapper'
7
7
  require 'hardmock/expector'
8
8
  require 'hardmock/expectation'
9
9
  require 'hardmock/expectation_builder'
10
+ require 'hardmock/stubbing'
10
11
 
11
12
  module Hardmock
12
13
 
@@ -73,7 +74,7 @@ module Hardmock
73
74
  # For more info on how to use your mocks, see Mock and Expectation
74
75
  #
75
76
  def create_mocks(*mock_names)
76
- @main_mock_control ||= MockControl.new
77
+ prepare_hardmock_control unless @main_mock_control
77
78
 
78
79
  mocks = {}
79
80
  mock_names.each do |mock_name|
@@ -89,6 +90,15 @@ module Hardmock
89
90
  return mocks.clone
90
91
  end
91
92
 
93
+ def prepare_hardmock_control
94
+ if @main_mock_control.nil?
95
+ @main_mock_control = MockControl.new
96
+ $main_mock_control = @main_mock_control
97
+ else
98
+ raise "@main_mock_control is already setup for this test!"
99
+ end
100
+ end
101
+
92
102
  alias :create_mock :create_mocks
93
103
 
94
104
  # Ensures that all expectations have been met. If not, VerifyException is
@@ -101,17 +111,34 @@ module Hardmock
101
111
  return unless @main_mock_control
102
112
  return if @main_mock_control.disappointed? and !force
103
113
  @main_mock_control.verify
114
+ ensure
115
+ @main_mock_control.clear_expectations if @main_mock_control
116
+ Hardmock.restore_all_stubbed_methods
117
+ $main_mock_control = nil
104
118
  end
105
119
 
120
+ # Purge the main MockControl of all expectations, restore all concrete stubbed/mocked methods
121
+ def clear_expectations
122
+ @main_mock_control.clear_expectations if @main_mock_control
123
+ Hardmock.restore_all_stubbed_methods
124
+ $main_mock_control = nil
125
+ end
106
126
 
127
+ # def self.set_main_mock_control(control)
128
+ # $main_mock_control = control
129
+ # end
107
130
 
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
108
135
 
109
136
  end
110
137
 
111
138
  # Insert Hardmock functionality into the TestCase base class
112
139
  require 'test/unit/testcase'
113
140
  unless Test::Unit::TestCase.instance_methods.include?('hardmock_teardown')
114
- class Test::Unit::TestCase
141
+ class Test::Unit::TestCase #:nodoc:#
115
142
  include Hardmock
116
143
  end
117
144
  end
@@ -3,13 +3,13 @@ require 'assert_error'
3
3
 
4
4
  class AssertErrorTest < Test::Unit::TestCase
5
5
 
6
- def test_assert_error
6
+ it "specfies an error type and message that should be raised" do
7
7
  assert_error RuntimeError, "Too funky" do
8
8
  raise RuntimeError.new("Too funky")
9
9
  end
10
10
  end
11
11
 
12
- def test_assert_error_message_doesnt_match
12
+ it "flunks if the error message is wrong" do
13
13
  err = assert_raise Test::Unit::AssertionFailedError do
14
14
  assert_error RuntimeError, "not good" do
15
15
  raise RuntimeError.new("Too funky")
@@ -19,7 +19,7 @@ class AssertErrorTest < Test::Unit::TestCase
19
19
  assert_match(/too funky/i, err.message)
20
20
  end
21
21
 
22
- def test_assert_error_type_doesnt_match
22
+ it "flunks if the error type is wrong" do
23
23
  err = assert_raise Test::Unit::AssertionFailedError do
24
24
  assert_error StandardError, "Too funky" do
25
25
  raise RuntimeError.new("Too funky")
@@ -29,13 +29,13 @@ class AssertErrorTest < Test::Unit::TestCase
29
29
  assert_match(/RuntimeError/i, err.message)
30
30
  end
31
31
 
32
- def test_assert_error_regexp_matching
32
+ it "can match error message text using a series of Regexps" do
33
33
  assert_error StandardError, /too/i, /funky/i do
34
34
  raise StandardError.new("Too funky")
35
35
  end
36
36
  end
37
37
 
38
- def test_assert_error_regexp_matching_fails
38
+ it "flunks if the error message doesn't match all the Regexps" do
39
39
  err = assert_raise Test::Unit::AssertionFailedError do
40
40
  assert_error StandardError, /way/i, /too/i, /funky/i do
41
41
  raise StandardError.new("Too funky")
@@ -44,7 +44,7 @@ class AssertErrorTest < Test::Unit::TestCase
44
44
  assert_match(/way/i, err.message)
45
45
  end
46
46
 
47
- def test_assert_error_no_matchine
47
+ it "can operate without any message specification" do
48
48
  assert_error StandardError do
49
49
  raise StandardError.new("ooof")
50
50
  end
@@ -15,11 +15,11 @@ class AutoVerifyTest < Test::Unit::TestCase
15
15
  # TESTS
16
16
  #
17
17
 
18
- def test_should_auto_verify_mocks_in_teardown
18
+ it "auto-verifies all mocks in teardown" do
19
19
  write_and_execute_test
20
20
  end
21
21
 
22
- def test_should_auto_verify_mocks_even_if_user_has_own_teardown
22
+ it "auto-verifies even if user defines own teardown" do
23
23
  @teardown_code =<<-EOM
24
24
  def teardown
25
25
  # just in the way
@@ -28,7 +28,7 @@ class AutoVerifyTest < Test::Unit::TestCase
28
28
  write_and_execute_test
29
29
  end
30
30
 
31
- def test_should_auto_verify_mocks_but_not_obscure_natural_failures
31
+ should "not obscure normal failures when verification fails" do
32
32
  @test_code =<<-EOM
33
33
  def test_setup_doomed_expectation
34
34
  create_mock :automobile
@@ -40,7 +40,7 @@ class AutoVerifyTest < Test::Unit::TestCase
40
40
  write_and_execute_test
41
41
  end
42
42
 
43
- def test_should_not_prevent_user_teardown_even_if_verification_fails
43
+ should "not skip user-defined teardown when verification fails" do
44
44
  @teardown_code =<<-EOM
45
45
  def teardown
46
46
  puts "User teardown"
@@ -50,7 +50,8 @@ class AutoVerifyTest < Test::Unit::TestCase
50
50
  assert_output_contains(/User teardown/)
51
51
  end
52
52
 
53
- def test_should_not_raise_error_if_verification_goes_according_to_plan
53
+ it "is quiet when verification is ok" do
54
+ # def test_should_not_raise_error_if_verification_goes_according_to_plan
54
55
  @test_code =<<-EOM
55
56
  def test_ok
56
57
  create_mock :automobile
@@ -70,7 +71,8 @@ class AutoVerifyTest < Test::Unit::TestCase
70
71
  assert_output_contains(/User teardown/)
71
72
  end
72
73
 
73
- def test_should_not_do_verification_if_user_teardown_explodes
74
+ should "not auto-verify if user teardown explodes" do
75
+ # def test_should_not_do_verification_if_user_teardown_explodes
74
76
  @teardown_code =<<-EOM
75
77
  def teardown
76
78
  raise "self destruct"
@@ -81,7 +83,7 @@ class AutoVerifyTest < Test::Unit::TestCase
81
83
  assert_output_contains(/self destruct/)
82
84
  end
83
85
 
84
- def test_should_not_obscure_inherited_teardown
86
+ it "plays nice with inherited teardown methods" do
85
87
  @full_code ||=<<-EOTEST
86
88
  require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
87
89
  require 'hardmock'
@@ -101,7 +103,7 @@ class AutoVerifyTest < Test::Unit::TestCase
101
103
  assert_output_contains(/Test helper teardown/)
102
104
  end
103
105
 
104
- def test_should_simultaneously_support_inherited_and_user_and_hardmock_teardown
106
+ it "plays nice with inherited and user-defined teardowns at the same time" do
105
107
  @full_code ||=<<-EOTEST
106
108
  require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
107
109
  class Test::Unit::TestCase
@@ -135,9 +137,6 @@ class AutoVerifyTest < Test::Unit::TestCase
135
137
  def run_test(tbody)
136
138
  File.open(temp_test_file,"w") { |f| f.print(tbody) }
137
139
  @test_output = `ruby #{temp_test_file} 2>&1`
138
- # puts "------------------------"
139
- # puts @test_output
140
- # puts "------------------------"
141
140
  end
142
141
 
143
142
  def remove_temp_test_file
@@ -14,7 +14,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
14
14
  # TESTS
15
15
  #
16
16
 
17
- def test_verify_should_raise_verify_error_if_expected_method_not_called
17
+ it "raises VerifyError if expected method not called" do
18
18
  @bird.expects.flap_flap
19
19
 
20
20
  err = assert_raise VerifyError do
@@ -23,7 +23,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
23
23
  assert_match(/unmet expectations/i, err.message)
24
24
  end
25
25
 
26
- def test_verify_should_not_raise_when_expected_calls_made_in_order
26
+ should "not raise when expected calls are made in order" do
27
27
  @bird.expects.flap_flap
28
28
  @bird.expects.bang
29
29
  @bird.expects.plop
@@ -35,7 +35,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
35
35
  @bird._verify
36
36
  end
37
37
 
38
- def test_should_raise_expectation_error_when_unexpected_method_called
38
+ it "raises ExpectationError when unexpected method are called" do
39
39
  @bird.expects.flap_flap
40
40
 
41
41
  err = assert_raise ExpectationError do
@@ -44,7 +44,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
44
44
  assert_match(/wrong method/i, err.message)
45
45
  end
46
46
 
47
- def test_bad_argument_call
47
+ it "raises ExpectationError on bad arguments" do
48
48
  @bird.expects.flap_flap(:swoosh)
49
49
 
50
50
  err = assert_raise ExpectationError do
@@ -53,7 +53,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
53
53
  assert_match(/wrong arguments/i, err.message)
54
54
  end
55
55
 
56
- def test_verify_should_raise_verify_error_when_not_all_expected_methods_called
56
+ it "raises VerifyError when not all expected methods are called" do
57
57
  @bird.expects.flap_flap
58
58
  @bird.expects.bang
59
59
  @bird.expects.plop
@@ -66,7 +66,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
66
66
  assert_match(/unmet expectations/i, err.message)
67
67
  end
68
68
 
69
- def test_should_raise_expectation_error_when_calls_made_out_of_order
69
+ it "raises ExpectationError when calls are made out of order" do
70
70
  @bird.expects.flap_flap
71
71
  @bird.expects.bang
72
72
  @bird.expects.plop
@@ -78,7 +78,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
78
78
  assert_match(/wrong method/i, err.message)
79
79
  end
80
80
 
81
- def test_should_return_given_value_when_specified
81
+ it "returns the configured value" do
82
82
  @bird.expects.plop.returns(':P')
83
83
  assert_equal ':P', @bird.plop
84
84
  @bird._verify
@@ -88,13 +88,13 @@ class DirectMockUsageTest < Test::Unit::TestCase
88
88
  @bird._verify
89
89
  end
90
90
 
91
- def test_should_return_nil_value_when_none_specified
91
+ it "returns nil when no return is specified" do
92
92
  @bird.expects.plop
93
93
  assert_nil @bird.plop
94
94
  @bird._verify
95
95
  end
96
96
 
97
- def test_raise_should_raise_given_exception_when_specified
97
+ it "raises the configured exception" do
98
98
  err = RuntimeError.new('shaq')
99
99
  @bird.expects.plop.raises(err)
100
100
  actual_err = assert_raise RuntimeError do
@@ -104,7 +104,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
104
104
  @bird._verify
105
105
  end
106
106
 
107
- def test_raise_should_raise_given_string_wrapped_in_runtime_error
107
+ it "raises a RuntimeError when told to 'raise' a string" do
108
108
  @bird.expects.plop.raises('shaq')
109
109
  err = assert_raise RuntimeError do
110
110
  @bird.plop
@@ -113,7 +113,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
113
113
  @bird._verify
114
114
  end
115
115
 
116
- def test_raise_should_raise_a_canned_runtime_error_if_nothing_given
116
+ it "raises a default RuntimeError" do
117
117
  @bird.expects.plop.raises
118
118
  err = assert_raise RuntimeError do
119
119
  @bird.plop
@@ -122,14 +122,14 @@ class DirectMockUsageTest < Test::Unit::TestCase
122
122
  @bird._verify
123
123
  end
124
124
 
125
- def test_should_be_happy_with_correct_expected_arguments
125
+ it "is quiet when correct arguments given" do
126
126
  thing = Object.new
127
127
  @bird.expects.plop(:big,'one',thing)
128
128
  @bird.plop(:big,'one',thing)
129
129
  @bird._verify
130
130
  end
131
131
 
132
- def test_should_raise_expectation_error_when_wrong_number_of_arguemnts_specified
132
+ it "raises ExpectationError when wrong number of arguments specified" do
133
133
  thing = Object.new
134
134
  @bird.expects.plop(:big,'one',thing)
135
135
  err = assert_raise ExpectationError do
@@ -156,7 +156,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
156
156
  @bird._verify
157
157
  end
158
158
 
159
- def test_should_raise_expectation_error_when_arguemnts_dont_match
159
+ it "raises ExpectationError when arguments don't match" do
160
160
  thing = Object.new
161
161
  @bird.expects.plop(:big,'one',thing)
162
162
  err = assert_raise ExpectationError do
@@ -166,7 +166,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
166
166
  @bird._verify
167
167
  end
168
168
 
169
- def test_should_yield_to_block_given
169
+ it "can use a block for custom reactions" do
170
170
  mitt = nil
171
171
  @bird.expects.plop { mitt = :ball }
172
172
  assert_nil mitt
@@ -182,7 +182,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
182
182
  @bird._verify
183
183
  end
184
184
 
185
- def test_shouldnt_care_about_arguments_if_block_given
185
+ it "passes mock-call arguments to the expectation block" do
186
186
  ball = nil
187
187
  mitt = nil
188
188
  @bird.expects.plop {|arg1,arg2|
@@ -197,7 +197,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
197
197
  @bird._verify
198
198
  end
199
199
 
200
- def test_should_check_arguments_if_specified_when_block_given
200
+ it "validates arguments if specified in addition to a block" do
201
201
  ball = nil
202
202
  mitt = nil
203
203
  @bird.expects.plop(:ball,:mitt) {|arg1,arg2|
@@ -244,7 +244,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
244
244
  @bird._verify
245
245
  end
246
246
 
247
- def test_runtime_blocks_get_passed_to_expectation_blocks
247
+ it "passes runtime blocks to the expectation block as the final argument" do
248
248
  runtime_block_called = false
249
249
  got_arg = nil
250
250
 
@@ -271,7 +271,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
271
271
  @bird._verify
272
272
  end
273
273
 
274
- def test_runtime_blocks_get_passed_to_expectation_blocks__no_arguments
274
+ it "passes the runtime block to the expectation block as sole argument if no other args come into play" do
275
275
  runtime_block_called = false
276
276
  @bird.expects.subscribe { |block| block.call }
277
277
  @bird.subscribe do
@@ -280,7 +280,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
280
280
  assert runtime_block_called, "The runtime block should have been invoked by the user block"
281
281
  end
282
282
 
283
- def test_expect_runtime_block_but_none_sent
283
+ it "provides nil as final argument if expectation block seems to want a block" do
284
284
  invoked = false
285
285
  @bird.expects.kablam(:scatter) { |shot,block|
286
286
  assert_equal :scatter, shot, "Wrong shot"
@@ -293,7 +293,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
293
293
  @bird._verify
294
294
  end
295
295
 
296
- def test_can_set_return_after_blocks
296
+ it "can set explicit return after an expectation block" do
297
297
  got = nil
298
298
  @bird.expects.kablam(:scatter) { |shot|
299
299
  got = shot
@@ -305,7 +305,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
305
305
  @bird._verify
306
306
  end
307
307
 
308
- def test_can_set_raises_after_blocks
308
+ it "can raise after an expectation block" do
309
309
  got = nil
310
310
  @bird.expects.kablam(:scatter) do |shot|
311
311
  got = shot
@@ -319,7 +319,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
319
319
  @bird._verify
320
320
  end
321
321
 
322
- def test_expectation_block_value_is_captured
322
+ it "stores the semantic value of the expectation block after it executes" do
323
323
  expectation = @bird.expects.kablam(:slug) { |shot|
324
324
  "The shot was #{shot}"
325
325
  }
@@ -336,7 +336,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
336
336
  end
337
337
 
338
338
 
339
- def test_expectation_block_value_is_used_for_return_value
339
+ it "uses the value of the expectation block as the default return value" do
340
340
  @bird.expects.kablam(:scatter) { |shot|
341
341
  "The shot was #{shot}"
342
342
  }
@@ -345,7 +345,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
345
345
  @bird._verify
346
346
  end
347
347
 
348
- def test_expectation_is_still_returned_when_using_returns
348
+ it "returns the Expectation even if 'returns' is used" do
349
349
  expectation = @bird.expects.kablam(:slug) { |shot|
350
350
  "The shot was #{shot}"
351
351
  }.returns :hosed
@@ -361,7 +361,7 @@ class DirectMockUsageTest < Test::Unit::TestCase
361
361
  @bird._verify
362
362
  end
363
363
 
364
- def test_expectation_is_still_returned_when_using_raises
364
+ it "returns the Expectation even if 'raises' is used" do
365
365
  expectation = @bird.expects.kablam(:slug) { |shot|
366
366
  "The shot was #{shot}"
367
367
  }.raises "aiee!"
@@ -378,13 +378,13 @@ class DirectMockUsageTest < Test::Unit::TestCase
378
378
  end
379
379
 
380
380
 
381
- def test_expect_assignment
381
+ it "supports assignment-style methods" do
382
382
  @bird.expects.size = "large"
383
383
  @bird.size = "large"
384
384
  @bird._verify
385
385
  end
386
386
 
387
- def test_expect_assignment_with_raise
387
+ it "supports assignments and raising (using explicit-method syntax)" do
388
388
  @bird.expects('size=','large').raises "boom"
389
389
 
390
390
  err = assert_raise RuntimeError do
@@ -4,33 +4,11 @@ require 'assert_error'
4
4
 
5
5
  class HardmockTest < Test::Unit::TestCase
6
6
 
7
- def setup
8
- end
9
-
10
- def teardown
11
- end
12
-
13
- #
14
- # HELPERS
15
- #
16
-
17
- def assert_mock_exists(name)
18
- assert_not_nil @all_mocks, "@all_mocks not here yet"
19
- mo = @all_mocks[name]
20
- assert_not_nil mo, "Mock '#{name}' not in @all_mocks"
21
- assert_kind_of Mock, mo, "Wrong type of object, wanted a Mock"
22
- assert_equal name.to_s, mo._name, "Mock '#{name}' had wrong name"
23
- ivar = self.instance_variable_get("@#{name}")
24
- assert_not_nil ivar, "Mock '#{name}' not set as ivar"
25
- assert_same mo, ivar, "Mock '#{name}' ivar not same as instance in @all_mocks"
26
- assert_same @main_mock_control, mo._control, "Mock '#{name}' doesn't share the main mock control"
27
- end
28
-
29
7
  #
30
8
  # TESTS
31
9
  #
32
10
 
33
- def test_create_mock_and_create_mocks
11
+ it "conveniently creates mocks using create_mock and create_mocks" do
34
12
  assert_nil @main_mock_control, "@main_mock_control not expected yet"
35
13
 
36
14
  h = create_mock :donkey
@@ -54,7 +32,7 @@ class HardmockTest < Test::Unit::TestCase
54
32
  assert_mock_exists :donkey
55
33
  end
56
34
 
57
- def test_expect
35
+ it "provides literal 'expects' syntax" do
58
36
  assert_nil @order, "Should be no @order yet"
59
37
  create_mock :order
60
38
  assert_not_nil @order, "@order should be built"
@@ -72,7 +50,7 @@ class HardmockTest < Test::Unit::TestCase
72
50
  verify_mocks
73
51
  end
74
52
 
75
- def test_typical_multi_mock_use
53
+ it "supports several mocks at once" do
76
54
  create_mocks :order_builder, :order, :customer
77
55
 
78
56
  @order_builder.expects.create_new_order.returns @order
@@ -88,7 +66,7 @@ class HardmockTest < Test::Unit::TestCase
88
66
  verify_mocks
89
67
  end
90
68
 
91
- def test_typical_multi_mock_use_out_of_order
69
+ it "enforces inter-mock call ordering" do
92
70
  create_mocks :order_builder, :order, :customer
93
71
 
94
72
  @order_builder.expects.create_new_order.returns @order
@@ -108,10 +86,6 @@ class HardmockTest < Test::Unit::TestCase
108
86
  assert_error VerifyError, /unmet expectations/i do
109
87
  verify_mocks
110
88
  end
111
-
112
- # Appease the verifier
113
- @order.account_no = 1234
114
- @order.save!
115
89
  end
116
90
 
117
91
  class UserPresenter
@@ -127,7 +101,7 @@ class HardmockTest < Test::Unit::TestCase
127
101
  end
128
102
  end
129
103
 
130
- def test_mvp_usage_pattern
104
+ it "makes MVP testing simple" do
131
105
  mox = create_mocks :model, :view
132
106
 
133
107
  data_change = @model.expects.when(:data_changes) { |evt,block| block }
@@ -150,7 +124,7 @@ class HardmockTest < Test::Unit::TestCase
150
124
  verify_mocks
151
125
  end
152
126
 
153
- def test_verify_mocks_repeated_anger
127
+ it "continues to function after verify, if verification error is controlled" do
154
128
  mox = create_mocks :model, :view
155
129
  data_change = @model.expects.when(:data_changes) { |evt,block| block }
156
130
  user_edit = @view.expects.when(:user_edited) { |evt,block| block }
@@ -174,18 +148,11 @@ class HardmockTest < Test::Unit::TestCase
174
148
  verify_mocks(false)
175
149
  end
176
150
 
177
- # Finish meeting expectations and see good verification behavior
178
- @view.user_name = "Da Croz"
179
- verify_mocks
180
-
181
151
  @model.expects.never_gonna_happen
182
152
 
183
153
  assert_error VerifyError, /unmet expectations/i, /never_gonna_happen/i do
184
154
  verify_mocks
185
155
  end
186
-
187
- # Appease the verifier
188
- @model.never_gonna_happen
189
156
  end
190
157
 
191
158
  class UserPresenterBroken
@@ -199,7 +166,7 @@ class HardmockTest < Test::Unit::TestCase
199
166
  end
200
167
  end
201
168
 
202
- def test_mvp_usage_with_failures_in_constructor
169
+ it "flunks for typical Presenter constructor wiring failure" do
203
170
  mox = create_mocks :model, :view
204
171
 
205
172
  data_change = @model.expects.when(:data_changes) { |evt,block| block }
@@ -213,16 +180,9 @@ class HardmockTest < Test::Unit::TestCase
213
180
  assert_match(/unmet expectations/i, err.message)
214
181
  assert_match(/view.when\(:user_edited\)/i, err.message)
215
182
 
216
- assert_error VerifyError, /unmet expectations/i do
217
- verify_mocks
218
- end
219
-
220
- # Appease the verifier
221
- @view.when(:user_edited)
222
-
223
183
  end
224
184
 
225
- def test_mvp_usage_pattern_with_convenience_trap
185
+ it "provides convenient event-subscription trap syntax for MVP testing" do
226
186
  mox = create_mocks :model, :view
227
187
 
228
188
  data_change = @model.trap.when(:data_changes)
@@ -245,6 +205,13 @@ class HardmockTest < Test::Unit::TestCase
245
205
  verify_mocks
246
206
  end
247
207
 
208
+ it "raises if you try to pass an expectation block to 'trap'" do
209
+ create_mock :model
210
+ assert_error Hardmock::ExpectationError, /blocks/i, /trap/i do
211
+ @model.trap.when(:some_event) do raise "huh?" end
212
+ end
213
+ end
214
+
248
215
  class Grinder
249
216
  def initialize(objects)
250
217
  @chute = objects[:chute]
@@ -259,7 +226,7 @@ class HardmockTest < Test::Unit::TestCase
259
226
  end
260
227
  end
261
228
 
262
- def test_internal_iteration_usage
229
+ it "lets you write clear iteration-oriented expectations" do
263
230
  grinder = Grinder.new create_mocks(:blade, :chute, :bucket)
264
231
 
265
232
  # Style 1: assertions on method args is done explicitly in block
@@ -290,7 +257,7 @@ class HardmockTest < Test::Unit::TestCase
290
257
  verify_mocks
291
258
  end
292
259
 
293
- def test_internal_iteration_using_yield
260
+ it "further supports iteration testing using 'yield'" do
294
261
  grinder = Grinder.new create_mocks(:blade, :chute, :bucket)
295
262
 
296
263
  @chute.expects.each_bean(:side_slot).yields :bean1, :bean2
@@ -322,7 +289,7 @@ class HardmockTest < Test::Unit::TestCase
322
289
  end
323
290
  end
324
291
 
325
- def test_internal_locking_scenario
292
+ it "makes mutex-style locking scenarios easy to test" do
326
293
  hurt = HurtLocker.new create_mocks(:locker, :store)
327
294
 
328
295
  @locker.expects.with_lock(:main).yields
@@ -333,7 +300,7 @@ class HardmockTest < Test::Unit::TestCase
333
300
  verify_mocks
334
301
  end
335
302
 
336
- def test_internal_locking_scenario_with_inner_error
303
+ it "makes it easy to simulate error in mutex-style locking scenarios" do
337
304
  hurt = HurtLocker.new create_mocks(:locker, :store)
338
305
  err = StandardError.new('fmshooop')
339
306
  @locker.expects.with_lock(:main).yields
@@ -345,7 +312,7 @@ class HardmockTest < Test::Unit::TestCase
345
312
  verify_mocks
346
313
  end
347
314
 
348
- def test_returning_false_actually_returns_false_and_not_nil
315
+ it "actually returns 'false' instead of nil when mocking boolean return values" do
349
316
  create_mock :car
350
317
  @car.expects.ignition_on?.returns(true)
351
318
  assert_equal true, @car.ignition_on?, "Should be true"
@@ -353,7 +320,7 @@ class HardmockTest < Test::Unit::TestCase
353
320
  assert_equal false, @car.ignition_on?, "Should be false"
354
321
  end
355
322
 
356
- def test_should_be_able_to_mock_some_methods_inherited_from_object
323
+ it "can mock most methods inherited from object using literal syntax" do
357
324
  target_methods = %w|id clone display dup eql? ==|
358
325
  create_mock :foo
359
326
  target_methods.each do |m|
@@ -362,14 +329,14 @@ class HardmockTest < Test::Unit::TestCase
362
329
  end
363
330
  end
364
331
 
365
- def test_should_support_expect_as_an_alias_for_expects
332
+ it "provides 'expect' as an alias for 'expects'" do
366
333
  create_mock :foo
367
334
  @foo.expect.boomboom
368
335
  @foo.boomboom
369
336
  verify_mocks
370
337
  end
371
338
 
372
- def test_should_not_raise_expectation_errors_for_some_methods_defined_on_object
339
+ it "does not interfere with a core subset of Object methods" do
373
340
  create_mock :foo
374
341
  @foo.method(:inspect)
375
342
  @foo.inspect
@@ -379,7 +346,7 @@ class HardmockTest < Test::Unit::TestCase
379
346
  verify_mocks
380
347
  end
381
348
 
382
- def test_should_support_raising_errors_within_expectation_blocks
349
+ it "can raise errors from within an expectation block" do
383
350
  create_mock :cat
384
351
  @cat.expects.meow do |arg|
385
352
  assert_equal "mix", arg
@@ -390,7 +357,7 @@ class HardmockTest < Test::Unit::TestCase
390
357
  end
391
358
  end
392
359
 
393
- def test_should_support_raising_errors_after_expectation_blocks
360
+ it "can raise errors AFTER an expectation block" do
394
361
  create_mock :cat
395
362
  @cat.expects.meow do |arg|
396
363
  assert_equal "mix", arg
@@ -400,7 +367,7 @@ class HardmockTest < Test::Unit::TestCase
400
367
  end
401
368
  end
402
369
 
403
- def test_should_raise_when_create_mocks_is_given_a_nil_name
370
+ it "raises an immediate error if a mock is created with a nil name (common mistake: create_mock @cat)" do
404
371
  # I make this mistake all the time: Typing in an instance var name instead of a symbol in create_mocks.
405
372
  # When you do that, you're effectively passing nil(s) in as mock names.
406
373
  assert_error ArgumentError, /'nil' is not a valid name for a mock/ do
@@ -408,10 +375,33 @@ class HardmockTest < Test::Unit::TestCase
408
375
  end
409
376
  end
410
377
 
411
- def test_should_display_mock_name_in_inspect_output
378
+ it "overrides 'inspect' to make nice output" do
412
379
  create_mock :hay_bailer
413
380
  assert_equal "<Mock hay_bailer>", @hay_bailer.inspect, "Wrong output from 'inspect'"
414
381
  end
415
382
 
383
+ it "raises is prepare_hardmock_control is invoked after create_mocks, or more than once" do
384
+ create_mock :hi_there
385
+ create_mocks :another, :one
386
+ assert_error RuntimeError, /already setup/ do
387
+ prepare_hardmock_control
388
+ end
389
+ end
390
+
391
+ #
392
+ # HELPERS
393
+ #
394
+
395
+ def assert_mock_exists(name)
396
+ assert_not_nil @all_mocks, "@all_mocks not here yet"
397
+ mo = @all_mocks[name]
398
+ assert_not_nil mo, "Mock '#{name}' not in @all_mocks"
399
+ assert_kind_of Mock, mo, "Wrong type of object, wanted a Mock"
400
+ assert_equal name.to_s, mo._name, "Mock '#{name}' had wrong name"
401
+ ivar = self.instance_variable_get("@#{name}")
402
+ assert_not_nil ivar, "Mock '#{name}' not set as ivar"
403
+ assert_same mo, ivar, "Mock '#{name}' ivar not same as instance in @all_mocks"
404
+ assert_same @main_mock_control, mo._control, "Mock '#{name}' doesn't share the main mock control"
405
+ end
416
406
  end
417
407
 
@@ -0,0 +1,274 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+ require 'hardmock'
3
+ require 'assert_error'
4
+
5
+ class StubbingTest < Test::Unit::TestCase
6
+
7
+ #
8
+ # TESTS
9
+ #
10
+
11
+ it "stubs a class method (and un-stubs after verify)" do
12
+ assert_equal "stones and gravel", Concrete.pour
13
+ assert_equal "glug glug", Jug.pour
14
+
15
+ Concrete.stubs!(:pour).returns("dust and plaster")
16
+
17
+ 3.times do
18
+ assert_equal "dust and plaster", Concrete.pour
19
+ end
20
+
21
+ assert_equal "glug glug", Jug.pour, "Jug's 'pour' method broken"
22
+ assert_equal "stones and gravel", Concrete._hardmock_original_pour, "Original 'pour' method not aliased"
23
+
24
+ assert_equal "For roads", Concrete.describe, "'describe' method broken"
25
+
26
+ verify_mocks
27
+
28
+ assert_equal "stones and gravel", Concrete.pour, "'pour' method not restored"
29
+ assert_equal "For roads", Concrete.describe, "'describe' method broken after verify"
30
+
31
+ end
32
+
33
+ it "stubs several class methods" do
34
+ Concrete.stubs!(:pour).returns("sludge")
35
+ Concrete.stubs!(:describe).returns("awful")
36
+ Jug.stubs!(:pour).returns("milk")
37
+
38
+ assert_equal "sludge", Concrete.pour
39
+ assert_equal "awful", Concrete.describe
40
+ assert_equal "milk", Jug.pour
41
+
42
+ verify_mocks
43
+
44
+ assert_equal "stones and gravel", Concrete.pour
45
+ assert_equal "For roads", Concrete.describe
46
+ assert_equal "glug glug", Jug.pour
47
+ end
48
+
49
+ it "stubs instance methods" do
50
+ slab = Concrete.new
51
+ assert_equal "bonk", slab.hit
52
+
53
+ slab.stubs!(:hit).returns("slap")
54
+ assert_equal "slap", slab.hit, "'hit' not stubbed"
55
+
56
+ verify_mocks
57
+
58
+ assert_equal "bonk", slab.hit, "'hit' not restored"
59
+ end
60
+
61
+ it "stubs instance methods without breaking class methods or other instances" do
62
+ slab = Concrete.new
63
+ scrape = Concrete.new
64
+ assert_equal "an instance", slab.describe
65
+ assert_equal "an instance", scrape.describe
66
+ assert_equal "For roads", Concrete.describe
67
+
68
+ slab.stubs!(:describe).returns("new instance describe")
69
+ assert_equal "new instance describe", slab.describe, "'describe' on instance not stubbed"
70
+ assert_equal "an instance", scrape.describe, "'describe' on 'scrape' instance broken"
71
+ assert_equal "For roads", Concrete.describe, "'describe' class method broken"
72
+
73
+ verify_mocks
74
+
75
+ assert_equal "an instance", slab.describe, "'describe' instance method not restored"
76
+ assert_equal "an instance", scrape.describe, "'describe' on 'scrape' instance broken after restore"
77
+ assert_equal "For roads", Concrete.describe, "'describe' class method broken after restore"
78
+ end
79
+
80
+ should "not allow stubbing of nonexistant class methods" do
81
+ assert_error(Hardmock::StubbingError, /cannot stub/i, /class method/i, /Concrete.funky/) do
82
+ Concrete.stubs!(:funky)
83
+ end
84
+ end
85
+
86
+ should "not allow stubbing of nonexistant instance methods" do
87
+ assert_error(Hardmock::StubbingError, /cannot stub/i, /method/i, /Concrete#my_inst_mth/) do
88
+ Concrete.new.stubs!(:my_inst_mth)
89
+ end
90
+ end
91
+
92
+ it "does nothing with a runtime block when simply stubbing" do
93
+ prepare_hardmock_control
94
+ slab = Concrete.new
95
+ slab.stubs!(:hit) do |nothing|
96
+ raise "BOOOMM!"
97
+ end
98
+ slab.hit
99
+ verify_mocks
100
+ end
101
+
102
+
103
+ #
104
+ # Per-method mocking on classes or instances
105
+ #
106
+
107
+ it "mocks specific methods on existing classes, and returns the class method to normal after verification" do
108
+ prepare_hardmock_control
109
+ assert_equal "stones and gravel", Concrete.pour, "Concrete.pour is already messed up"
110
+
111
+ Concrete.expects!(:pour).returns("ALIGATORS")
112
+ assert_equal "ALIGATORS", Concrete.pour
113
+
114
+ verify_mocks
115
+ assert_equal "stones and gravel", Concrete.pour, "Concrete.pour not restored"
116
+ end
117
+
118
+ it "flunks if expected class method is not invoked" do
119
+ prepare_hardmock_control
120
+ Concrete.expects!(:pour).returns("ALIGATORS")
121
+ assert_error(Hardmock::VerifyError, /Concrete.pour/, /unmet expectations/i) do
122
+ verify_mocks
123
+ end
124
+ clear_expectations
125
+ end
126
+
127
+ it "supports all normal mock functionality for class methods" do
128
+ prepare_hardmock_control
129
+ Concrete.expects!(:pour, "two tons").returns("mice")
130
+ Concrete.expects!(:pour, "three tons").returns("cats")
131
+ Concrete.expects!(:pour, "four tons").raises("Can't do it")
132
+ Concrete.expects!(:pour) do |some, args|
133
+ "==#{some}+#{args}=="
134
+ end
135
+
136
+ assert_equal "mice", Concrete.pour("two tons")
137
+ assert_equal "cats", Concrete.pour("three tons")
138
+ assert_error(RuntimeError, /Can't do it/) do
139
+ Concrete.pour("four tons")
140
+ end
141
+ assert_equal "==first+second==", Concrete.pour("first","second")
142
+ end
143
+
144
+
145
+ it "enforces inter-mock ordering when mocking class methods" do
146
+ create_mocks :truck, :foreman
147
+
148
+ @truck.expects.backup
149
+ Concrete.expects!(:pour, "something")
150
+ @foreman.expects.shout
151
+
152
+ @truck.backup
153
+ assert_error Hardmock::ExpectationError, /wrong/i, /expected call/i, /Concrete.pour/ do
154
+ @foreman.shout
155
+ end
156
+ assert_error Hardmock::VerifyError, /unmet expectations/i, /foreman.shout/ do
157
+ verify_mocks
158
+ end
159
+ clear_expectations
160
+ end
161
+
162
+ should "not allow mocking non-existant class methods" do
163
+ prepare_hardmock_control
164
+ assert_error Hardmock::StubbingError, /non-existant/, /something/ do
165
+ Concrete.expects!(:something)
166
+ end
167
+ end
168
+
169
+ it "mocks specific methods on existing instances, then restore them after verify" do
170
+ prepare_hardmock_control
171
+ slab = Concrete.new
172
+ assert_equal "bonk", slab.hit
173
+
174
+ slab.expects!(:hit).returns("slap")
175
+ assert_equal "slap", slab.hit, "'hit' not stubbed"
176
+
177
+ verify_mocks
178
+ assert_equal "bonk", slab.hit, "'hit' not restored"
179
+ end
180
+
181
+ it "flunks if expected instance method is not invoked" do
182
+ prepare_hardmock_control
183
+ slab = Concrete.new
184
+ slab.expects!(:hit)
185
+
186
+ assert_error Hardmock::VerifyError, /unmet expectations/i, /Concrete.hit/ do
187
+ verify_mocks
188
+ end
189
+ clear_expectations
190
+ end
191
+
192
+ it "supports all normal mock functionality for instance methods" do
193
+ prepare_hardmock_control
194
+ slab = Concrete.new
195
+
196
+ slab.expects!(:hit, "soft").returns("hey")
197
+ slab.expects!(:hit, "hard").returns("OOF")
198
+ slab.expects!(:hit).raises("stoppit")
199
+ slab.expects!(:hit) do |some, args|
200
+ "==#{some}+#{args}=="
201
+ end
202
+
203
+ assert_equal "hey", slab.hit("soft")
204
+ assert_equal "OOF", slab.hit("hard")
205
+ assert_error(RuntimeError, /stoppit/) do
206
+ slab.hit
207
+ end
208
+ assert_equal "==first+second==", slab.hit("first","second")
209
+
210
+ end
211
+
212
+ it "enforces inter-mock ordering when mocking instance methods" do
213
+ create_mocks :truck, :foreman
214
+ slab1 = Concrete.new
215
+ slab2 = Concrete.new
216
+
217
+ @truck.expects.backup
218
+ slab1.expects!(:hit)
219
+ @foreman.expects.shout
220
+ slab2.expects!(:hit)
221
+ @foreman.expects.whatever
222
+
223
+ @truck.backup
224
+ slab1.hit
225
+ @foreman.shout
226
+ assert_error Hardmock::ExpectationError, /wrong/i, /expected call/i, /Concrete.hit/ do
227
+ @foreman.whatever
228
+ end
229
+ assert_error Hardmock::VerifyError, /unmet expectations/i, /foreman.whatever/ do
230
+ verify_mocks
231
+ end
232
+ clear_expectations
233
+ end
234
+
235
+ should "not allow mocking non-existant instance methods" do
236
+ prepare_hardmock_control
237
+ slab = Concrete.new
238
+ assert_error Hardmock::StubbingError, /non-existant/, /something/ do
239
+ slab.expects!(:something)
240
+ end
241
+ end
242
+
243
+ should "support expectations that deal with runtime blocks"
244
+
245
+ #
246
+ # HELPERS
247
+ #
248
+
249
+ class Concrete
250
+ def self.pour
251
+ "stones and gravel"
252
+ end
253
+
254
+ def self.describe
255
+ "For roads"
256
+ end
257
+
258
+ def hit
259
+ "bonk"
260
+ end
261
+
262
+ def describe
263
+ "an instance"
264
+ end
265
+ end
266
+
267
+ class Jug
268
+ def self.pour
269
+ "glug glug"
270
+ end
271
+ end
272
+
273
+ end
274
+
data/test/test_helper.rb CHANGED
@@ -20,4 +20,27 @@ class Test::Unit::TestCase
20
20
  end
21
21
  return false
22
22
  end
23
+
24
+ def self.it(str, &block)
25
+ make_test_case "it", str, &block
26
+ end
27
+
28
+ def self.should(str, &block)
29
+ make_test_case "should", str, &block
30
+ end
31
+
32
+ def self.make_test_case(prefix, str, &block)
33
+ tname = self.name.sub(/Test$/,'')
34
+ if block
35
+ define_method "test #{prefix} #{str}" do
36
+ # phrase = str
37
+ # phrase = prefix + " " + phrase unless prefix == "it"
38
+ # puts "#{tname} #{phrase}..."
39
+ instance_eval &block
40
+ end
41
+ else
42
+ puts ">>> UNIMPLEMENTED CASE: #{tname}: #{str}"
43
+ end
44
+ end
45
+
23
46
  end
@@ -1,6 +1,7 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
2
  require 'hardmock/expectation'
3
3
  require 'hardmock/errors'
4
+ require 'assert_error'
4
5
 
5
6
  class ExpectationTest < Test::Unit::TestCase
6
7
  include Hardmock
@@ -344,4 +345,14 @@ class ExpectationTest < Test::Unit::TestCase
344
345
  assert_match(/"a", "b", "c"/i, err.message)
345
346
  assert_equal [], things, "Wrong things"
346
347
  end
348
+
349
+ def test_yields_bad_block_arity
350
+ se = Expectation.new(:mock => @mock, :method => 'do_later', :arguments => [] )
351
+ se.yields
352
+
353
+ assert_error Hardmock::ExpectationError, /block/i, /expected/i, /no param/i, /got 2/i do
354
+ se.apply_method_call(@mock,'do_later',[],lambda { |doesnt,match| raise "Surprise!" } )
355
+ end
356
+ end
357
+
347
358
  end
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.2.3
7
- date: 2007-04-28 00:00:00 -04:00
6
+ version: 1.3.0
7
+ date: 2007-11-12 00:00:00 -05:00
8
8
  summary: A strict, ordered, expectation-oriented mock object library.
9
9
  require_paths:
10
10
  - lib
@@ -38,6 +38,7 @@ files:
38
38
  - lib/hardmock/method_cleanout.rb
39
39
  - lib/hardmock/mock.rb
40
40
  - lib/hardmock/mock_control.rb
41
+ - lib/hardmock/stubbing.rb
41
42
  - lib/hardmock/trapper.rb
42
43
  - lib/hardmock/utils.rb
43
44
  - lib/tasks/rdoc_options.rb
@@ -46,6 +47,7 @@ files:
46
47
  - test/functional/auto_verify_test.rb
47
48
  - test/functional/direct_mock_usage_test.rb
48
49
  - test/functional/hardmock_test.rb
50
+ - test/functional/stubbing_test.rb
49
51
  - test/unit/expectation_builder_test.rb
50
52
  - test/unit/expectation_test.rb
51
53
  - test/unit/expector_test.rb
@@ -66,6 +68,7 @@ test_files:
66
68
  - test/functional/auto_verify_test.rb
67
69
  - test/functional/direct_mock_usage_test.rb
68
70
  - test/functional/hardmock_test.rb
71
+ - test/functional/stubbing_test.rb
69
72
  - test/unit/expectation_builder_test.rb
70
73
  - test/unit/expectation_test.rb
71
74
  - test/unit/expector_test.rb