flexmock 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +34 -25
- data/TAGS +2192 -117
- data/lib/flexmock/core.rb +6 -1
- data/lib/flexmock/default_framework_adapter.rb +1 -0
- data/lib/flexmock/expectation.rb +10 -2
- data/lib/flexmock/expectation_director.rb +2 -2
- data/lib/flexmock/mock_container.rb +14 -13
- data/lib/flexmock/partial_mock.rb +13 -4
- data/lib/flexmock/recorder.rb +2 -1
- data/lib/flexmock/rspec.rb +1 -0
- data/lib/flexmock/spy_describers.rb +13 -3
- data/lib/flexmock/test_unit_integration.rb +11 -0
- data/lib/flexmock/validators.rb +35 -8
- data/lib/flexmock/version.rb +1 -1
- data/test/assert_spy_called_test.rb +17 -0
- data/test/base_class_test.rb +11 -1
- data/test/demeter_mocking_test.rb +1 -1
- data/test/new_instances_test.rb +1 -1
- data/test/record_mode_test.rb +6 -6
- data/test/rspec_integration/integration_spec.rb +1 -1
- data/test/should_receive_test.rb +38 -22
- data/test/test_setup.rb +41 -1
- metadata +2 -2
data/lib/flexmock/core.rb
CHANGED
@@ -197,9 +197,14 @@ class FlexMock
|
|
197
197
|
# See Expectation for a list of declarators that can be used.
|
198
198
|
#
|
199
199
|
def should_receive(*args)
|
200
|
+
location = caller.first
|
201
|
+
flexmock_define_expectation(location, *args)
|
202
|
+
end
|
203
|
+
|
204
|
+
def flexmock_define_expectation(location, *args)
|
200
205
|
@last_expectation = ContainerHelper.parse_should_args(self, args) do |sym|
|
201
206
|
@expectations[sym] ||= ExpectationDirector.new(sym)
|
202
|
-
result = Expectation.new(self, sym)
|
207
|
+
result = Expectation.new(self, sym, location)
|
203
208
|
@expectations[sym] << result
|
204
209
|
override_existing_method(sym) if flexmock_respond_to?(sym)
|
205
210
|
result = ExplicitNeeded.new(result, sym, @base_class) if
|
data/lib/flexmock/expectation.rb
CHANGED
@@ -32,9 +32,10 @@ class FlexMock
|
|
32
32
|
attr_accessor :mock
|
33
33
|
|
34
34
|
# Create an expectation for a method named +sym+.
|
35
|
-
def initialize(mock, sym)
|
35
|
+
def initialize(mock, sym, location)
|
36
36
|
@mock = mock
|
37
37
|
@sym = sym
|
38
|
+
@location = location
|
38
39
|
@expected_args = nil
|
39
40
|
@count_validators = []
|
40
41
|
@count_validator_class = ExactCountValidator
|
@@ -392,6 +393,13 @@ class FlexMock
|
|
392
393
|
expectations.defaultify_expectation(self) if expectations
|
393
394
|
end
|
394
395
|
|
396
|
+
def flexmock_location_filter
|
397
|
+
yield
|
398
|
+
rescue Exception => ex
|
399
|
+
ex.backtrace.insert(0, @location)
|
400
|
+
raise ex
|
401
|
+
end
|
402
|
+
|
395
403
|
end
|
396
404
|
|
397
405
|
##########################################################################
|
@@ -434,7 +442,7 @@ class FlexMock
|
|
434
442
|
# Start a new method expectation. The following constraints will be
|
435
443
|
# applied to the new expectation.
|
436
444
|
def should_receive(*args, &block)
|
437
|
-
@expectations.first.mock.
|
445
|
+
@expectations.first.mock.flexmock_define_expectation(caller.first, *args, &block)
|
438
446
|
end
|
439
447
|
|
440
448
|
# Return a string representations
|
@@ -37,8 +37,8 @@ class FlexMock
|
|
37
37
|
# criteria.
|
38
38
|
def call(*args)
|
39
39
|
exp = find_expectation(*args)
|
40
|
-
FlexMock.check(
|
41
|
-
FlexMock.format_args(@sym, args)) { ! exp.nil? }
|
40
|
+
FlexMock.check(
|
41
|
+
"no matching handler found for " + FlexMock.format_args(@sym, args)) { ! exp.nil? }
|
42
42
|
exp.verify_call(*args)
|
43
43
|
end
|
44
44
|
|
@@ -117,6 +117,7 @@ class FlexMock
|
|
117
117
|
# the mock object.
|
118
118
|
#
|
119
119
|
def flexmock(*args)
|
120
|
+
location = caller.first
|
120
121
|
name = nil
|
121
122
|
quick_defs = {}
|
122
123
|
domain_obj = nil
|
@@ -160,10 +161,10 @@ class FlexMock
|
|
160
161
|
result = mock
|
161
162
|
end
|
162
163
|
mock.flexmock_based_on(base_class) if base_class
|
163
|
-
mock.
|
164
|
+
mock.flexmock_define_expectation(location, quick_defs)
|
164
165
|
yield(mock) if block_given?
|
165
166
|
flexmock_remember(mock)
|
166
|
-
ContainerHelper.add_model_methods(mock, model_class, id) if model_class
|
167
|
+
ContainerHelper.add_model_methods(mock, model_class, id, location) if model_class
|
167
168
|
result
|
168
169
|
end
|
169
170
|
alias flexstub flexmock
|
@@ -230,29 +231,29 @@ class FlexMock
|
|
230
231
|
|
231
232
|
# Automatically add mocks for some common methods in ActiveRecord
|
232
233
|
# models.
|
233
|
-
def add_model_methods(mock, model_class, id)
|
234
|
+
def add_model_methods(mock, model_class, id, location)
|
234
235
|
container = mock.flexmock_container
|
235
236
|
|
236
237
|
mock_errors = container.flexmock("errors")
|
237
|
-
mock_errors.
|
238
|
-
mock_errors.
|
238
|
+
mock_errors.flexmock_define_expectation(location, :count).and_return(0).by_default
|
239
|
+
mock_errors.flexmock_define_expectation(location, :full_messages).and_return([]).by_default
|
239
240
|
|
240
|
-
mock.
|
241
|
-
mock.
|
242
|
-
mock.
|
243
|
-
mock.
|
244
|
-
mock.
|
241
|
+
mock.flexmock_define_expectation(location, :id).and_return(id).by_default
|
242
|
+
mock.flexmock_define_expectation(location, :to_params).and_return(id.to_s).by_default
|
243
|
+
mock.flexmock_define_expectation(location, :new_record?).and_return(false).by_default
|
244
|
+
mock.flexmock_define_expectation(location, :class).and_return(model_class).by_default
|
245
|
+
mock.flexmock_define_expectation(location, :errors).and_return(mock_errors).by_default
|
245
246
|
|
246
247
|
# HACK: Ruby 1.9 needs the following lambda so that model_class
|
247
248
|
# is correctly bound below.
|
248
249
|
lambda { }
|
249
|
-
mock.
|
250
|
+
mock.flexmock_define_expectation(location, :is_a?).with(any).and_return { |other|
|
250
251
|
other == model_class
|
251
252
|
}.by_default
|
252
|
-
mock.
|
253
|
+
mock.flexmock_define_expectation(location, :instance_of?).with(any).and_return { |other|
|
253
254
|
other == model_class
|
254
255
|
}.by_default
|
255
|
-
mock.
|
256
|
+
mock.flexmock_define_expectation(location, :kind_of?).with(any).and_return { |other|
|
256
257
|
model_class.ancestors.include?(other)
|
257
258
|
}.by_default
|
258
259
|
end
|
@@ -33,6 +33,7 @@ class FlexMock
|
|
33
33
|
|
34
34
|
MOCK_METHODS = [
|
35
35
|
:should_receive, :new_instances,
|
36
|
+
:should_receive_with_location,
|
36
37
|
:flexmock_get, :flexmock_teardown, :flexmock_verify,
|
37
38
|
:flexmock_received?, :flexmock_calls,
|
38
39
|
]
|
@@ -79,11 +80,16 @@ class FlexMock
|
|
79
80
|
#
|
80
81
|
# See Expectation for a list of declarators that can be used.
|
81
82
|
def should_receive(*args)
|
83
|
+
location = caller.first
|
84
|
+
flexmock_define_expectation(location, *args)
|
85
|
+
end
|
86
|
+
|
87
|
+
def flexmock_define_expectation(location, *args)
|
82
88
|
ContainerHelper.parse_should_args(@mock, args) do |sym|
|
83
89
|
unless @methods_proxied.include?(sym)
|
84
90
|
hide_existing_method(sym)
|
85
91
|
end
|
86
|
-
ex = @mock.
|
92
|
+
ex = @mock.flexmock_define_expectation(location, sym)
|
87
93
|
ex.mock = self
|
88
94
|
ex
|
89
95
|
end
|
@@ -123,14 +129,17 @@ class FlexMock
|
|
123
129
|
#
|
124
130
|
def new_instances(*allocators, &block)
|
125
131
|
fail ArgumentError, "new_instances requires a Class to stub" unless Class === @obj
|
132
|
+
location = caller.first
|
126
133
|
allocators = [:new] if allocators.empty?
|
127
134
|
result = ExpectationRecorder.new
|
128
135
|
allocators.each do |allocate_method|
|
129
136
|
check_allocate_method(allocate_method)
|
130
|
-
# HACK: Without the following lambda, Ruby 1.9
|
131
|
-
# the allocate_method parameter
|
137
|
+
# HACK: Without the following lambda, Some versions of Ruby 1.9
|
138
|
+
# would not bind the allocate_method parameter
|
139
|
+
# correctly. I don't think it is necessary for recent
|
140
|
+
# versions.
|
132
141
|
lambda { }
|
133
|
-
self.
|
142
|
+
self.flexmock_define_expectation(location, allocate_method).and_return { |*args|
|
134
143
|
new_obj = invoke_original(allocate_method, args)
|
135
144
|
mock = flexmock_container.flexmock(new_obj)
|
136
145
|
block.call(mock) if block_given?
|
data/lib/flexmock/recorder.rb
CHANGED
@@ -57,7 +57,8 @@ class FlexMock
|
|
57
57
|
# Record an expectation for receiving the method +sym+ with the
|
58
58
|
# given arguments.
|
59
59
|
def method_missing(sym, *args, &block)
|
60
|
-
|
60
|
+
location = caller.first
|
61
|
+
expectation = @mock.flexmock_define_expectation(location, sym).and_return(&block)
|
61
62
|
if strict?
|
62
63
|
args = args.collect { |arg| eq(arg) }
|
63
64
|
expectation.with(*args).ordered.once
|
data/lib/flexmock/rspec.rb
CHANGED
@@ -19,9 +19,19 @@ class FlexMock
|
|
19
19
|
result << times_description(options[:times])
|
20
20
|
result << block_description(options[:with_block])
|
21
21
|
result << ".\n"
|
22
|
-
result <<
|
23
|
-
|
24
|
-
|
22
|
+
result << describe_calls(spy)
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
def describe_calls(spy)
|
27
|
+
result = ''
|
28
|
+
if spy.flexmock_calls.empty?
|
29
|
+
result << "No messages have been received\n"
|
30
|
+
else
|
31
|
+
result << "The following messages have been received:\n"
|
32
|
+
spy.flexmock_calls.each do |call_sym, call_args|
|
33
|
+
result << " " << call_description(call_sym, call_args) << "\n"
|
34
|
+
end
|
25
35
|
end
|
26
36
|
result
|
27
37
|
end
|
@@ -46,6 +46,17 @@ class FlexMock
|
|
46
46
|
#
|
47
47
|
class TestUnitFrameworkAdapter
|
48
48
|
include Test::Unit::Assertions
|
49
|
+
|
50
|
+
def assert_block(msg, &block)
|
51
|
+
unless yield
|
52
|
+
msg = msg.call if msg.is_a?(Proc)
|
53
|
+
super(msg) { false }
|
54
|
+
end
|
55
|
+
rescue assertion_failed_error => ex
|
56
|
+
ex.message.sub!(/Expected block to return true value./,'')
|
57
|
+
raise ex
|
58
|
+
end
|
59
|
+
|
49
60
|
def assertion_failed_error
|
50
61
|
defined?(Test::Unit::AssertionFailedError) ? Test::Unit::AssertionFailedError : MiniTest::Assertion
|
51
62
|
end
|
data/lib/flexmock/validators.rb
CHANGED
@@ -10,6 +10,7 @@
|
|
10
10
|
#+++
|
11
11
|
|
12
12
|
require 'flexmock/noop'
|
13
|
+
require 'flexmock/spy_describers'
|
13
14
|
|
14
15
|
class FlexMock
|
15
16
|
|
@@ -17,6 +18,8 @@ class FlexMock
|
|
17
18
|
# Base class for all the count validators.
|
18
19
|
#
|
19
20
|
class CountValidator
|
21
|
+
include FlexMock::SpyDescribers
|
22
|
+
|
20
23
|
def initialize(expectation, limit)
|
21
24
|
@exp = expectation
|
22
25
|
@limit = limit
|
@@ -28,6 +31,10 @@ class FlexMock
|
|
28
31
|
def eligible?(n)
|
29
32
|
n < @limit
|
30
33
|
end
|
34
|
+
|
35
|
+
def calls(n)
|
36
|
+
n == 1 ? "call" : "calls"
|
37
|
+
end
|
31
38
|
end
|
32
39
|
|
33
40
|
####################################################################
|
@@ -37,8 +44,16 @@ class FlexMock
|
|
37
44
|
# Validate that the method expectation was called exactly +n+
|
38
45
|
# times.
|
39
46
|
def validate(n)
|
40
|
-
|
41
|
-
|
47
|
+
@exp.flexmock_location_filter do
|
48
|
+
FlexMock.framework_adapter.assert_block(
|
49
|
+
lambda {
|
50
|
+
"Method '#{@exp}' called incorrect number of times\n" +
|
51
|
+
"#{@limit} #{calls(@limit)} expected\n" +
|
52
|
+
"#{n} matching #{calls(n)} found\n" +
|
53
|
+
describe_calls(@exp.mock)
|
54
|
+
}
|
55
|
+
) { @limit == n }
|
56
|
+
end
|
42
57
|
end
|
43
58
|
end
|
44
59
|
|
@@ -49,9 +64,15 @@ class FlexMock
|
|
49
64
|
# Validate the method expectation was called no more than +n+
|
50
65
|
# times.
|
51
66
|
def validate(n)
|
52
|
-
|
53
|
-
|
54
|
-
|
67
|
+
@exp.flexmock_location_filter do
|
68
|
+
FlexMock.framework_adapter.assert_block(
|
69
|
+
lambda {
|
70
|
+
"Method '#{@exp}' called incorrect number of times\n" +
|
71
|
+
"At least #{@limit} #{calls(@limit)} expected\n" +
|
72
|
+
"#{n} matching #{calls(n)} found\n" +
|
73
|
+
describe_calls(@exp.mock)
|
74
|
+
}) { n >= @limit }
|
75
|
+
end
|
55
76
|
end
|
56
77
|
|
57
78
|
# If the expectation has been called +n+ times, is it still
|
@@ -69,9 +90,15 @@ class FlexMock
|
|
69
90
|
class AtMostCountValidator < CountValidator
|
70
91
|
# Validate the method expectation was called at least +n+ times.
|
71
92
|
def validate(n)
|
72
|
-
|
73
|
-
|
74
|
-
|
93
|
+
@exp.flexmock_location_filter do
|
94
|
+
FlexMock.framework_adapter.assert_block(
|
95
|
+
lambda {
|
96
|
+
"Method '#{@exp}' called incorrect number of times\n" +
|
97
|
+
"At most #{@limit} #{calls(@limit)} expected\n" +
|
98
|
+
"#{n} matching #{calls(n)} found\n" +
|
99
|
+
describe_calls(@exp.mock)
|
100
|
+
}) { n <= @limit }
|
101
|
+
end
|
75
102
|
end
|
76
103
|
end
|
77
104
|
end
|
data/lib/flexmock/version.rb
CHANGED
@@ -76,6 +76,23 @@ class AssertSpyCalledTest < Test::Unit::TestCase
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
+
def test_assert_error_lists_calls_actually_made
|
80
|
+
spy.foo
|
81
|
+
spy.bar(1)
|
82
|
+
ex = assert_fails(/The following messages have been received/) do
|
83
|
+
assert_spy_called spy, :baz
|
84
|
+
end
|
85
|
+
assert_match(/ foo\(\)/, ex.message)
|
86
|
+
assert_match(/ bar\(1\)/, ex.message)
|
87
|
+
assert_no_match(/ baz\(\)/, ex.message)
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_assert_errors_say_no_calls_made
|
91
|
+
ex = assert_fails(/No messages have been received/) do
|
92
|
+
assert_spy_called spy, :baz
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
79
96
|
private
|
80
97
|
|
81
98
|
def assert_fails(message_pattern)
|
data/test/base_class_test.rb
CHANGED
@@ -21,10 +21,20 @@ class BaseClassTest < Test::Unit::TestCase
|
|
21
21
|
@mock ||= flexmock(:on, FooBar)
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
24
|
+
def test_base_class_auto_mocks_class
|
25
25
|
assert_equal FooBar, mock.class
|
26
26
|
end
|
27
27
|
|
28
|
+
def test_base_class_auto_mocks_base_class_methods
|
29
|
+
assert_equal FlexMock.undefined, mock.foo
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_base_class_does_not_mock_non_base_class_methods
|
33
|
+
assert_raise(NoMethodError) do
|
34
|
+
mock.fuzz
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
28
38
|
def test_can_stub_existing_methods
|
29
39
|
mock.should_receive(:foo => :bar)
|
30
40
|
assert_equal :bar, mock.foo
|
@@ -65,7 +65,7 @@ class TestDemeterMocking < Test::Unit::TestCase
|
|
65
65
|
def test_conflicting_mock_declarations_in_reverse_order_does_not_raise_error
|
66
66
|
# Not all conflicting definitions can be detected.
|
67
67
|
m = flexmock("A")
|
68
|
-
assert_failure
|
68
|
+
assert_failure do
|
69
69
|
m.should_receive("child.other").and_return(:other)
|
70
70
|
m.should_receive("child").and_return(:xyzzy)
|
71
71
|
assert_equal :xyzzy, m.child.other
|
data/test/new_instances_test.rb
CHANGED
@@ -96,7 +96,7 @@ class TestNewInstances < Test::Unit::TestCase
|
|
96
96
|
|
97
97
|
Dog.new
|
98
98
|
ex = assert_raise(assertion_failed_error) { flexmock_teardown }
|
99
|
-
assert_match(/method 'bark\(.*\)' called incorrect number of times
|
99
|
+
assert_match(/method 'bark\(.*\)' called incorrect number of times/i, ex.message)
|
100
100
|
end
|
101
101
|
|
102
102
|
def test_new_instances_reports_error_on_non_classes
|
data/test/record_mode_test.rb
CHANGED
@@ -71,7 +71,7 @@ class TestRecordMode < Test::Unit::TestCase
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def test_recording_mode_should_validate_args_with_equals
|
74
|
-
|
74
|
+
assert_mock_failure(:deep => true, :line => __LINE__+5) do
|
75
75
|
FlexMock.use("mock") do |mock|
|
76
76
|
mock.should_expect do |r|
|
77
77
|
r.f(1)
|
@@ -82,7 +82,7 @@ class TestRecordMode < Test::Unit::TestCase
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def test_recording_mode_should_allow_arg_contraint_validation
|
85
|
-
|
85
|
+
assert_mock_failure(:deep => true, :line => __LINE__+5) do
|
86
86
|
FlexMock.use("mock") do |mock|
|
87
87
|
mock.should_expect do |r|
|
88
88
|
r.f(1)
|
@@ -93,7 +93,7 @@ class TestRecordMode < Test::Unit::TestCase
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def test_recording_mode_should_handle_multiplicity_contraints
|
96
|
-
|
96
|
+
assert_mock_failure(:line => __LINE__+3) do
|
97
97
|
FlexMock.use("mock") do |mock|
|
98
98
|
mock.should_expect do |r|
|
99
99
|
r.f { :result }.once
|
@@ -105,7 +105,7 @@ class TestRecordMode < Test::Unit::TestCase
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def test_strict_record_mode_requires_exact_argument_matches
|
108
|
-
|
108
|
+
assert_mock_failure(:deep => true, :line => __LINE__+6) do
|
109
109
|
FlexMock.use("mock") do |mock|
|
110
110
|
mock.should_expect do |rec|
|
111
111
|
rec.should_be_strict
|
@@ -117,7 +117,7 @@ class TestRecordMode < Test::Unit::TestCase
|
|
117
117
|
end
|
118
118
|
|
119
119
|
def test_strict_record_mode_requires_exact_ordering
|
120
|
-
|
120
|
+
assert_mock_failure(:deep => true, :line => __LINE__+8) do
|
121
121
|
FlexMock.use("mock") do |mock|
|
122
122
|
mock.should_expect do |rec|
|
123
123
|
rec.should_be_strict
|
@@ -131,7 +131,7 @@ class TestRecordMode < Test::Unit::TestCase
|
|
131
131
|
end
|
132
132
|
|
133
133
|
def test_strict_record_mode_requires_once
|
134
|
-
|
134
|
+
assert_mock_failure(:deep => true, :line => __LINE__+4) do
|
135
135
|
FlexMock.use("mock") do |mock|
|
136
136
|
mock.should_expect do |rec|
|
137
137
|
rec.should_be_strict
|