flexmock 0.6.4 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +8 -0
- data/README +116 -3
- data/Rakefile +5 -5
- data/TAGS +396 -282
- data/doc/releases/flexmock-0.7.0.rdoc +138 -0
- data/lib/flexmock/base.rb +2 -1
- data/lib/flexmock/core.rb +30 -29
- data/lib/flexmock/core_class_methods.rb +21 -30
- data/lib/flexmock/deprecated_methods.rb +62 -0
- data/lib/flexmock/expectation.rb +101 -21
- data/lib/flexmock/expectation_director.rb +10 -5
- data/lib/flexmock/mock_container.rb +144 -29
- data/lib/flexmock/ordering.rb +51 -0
- data/lib/flexmock/partial_mock.rb +23 -22
- data/test/asserts.rb +34 -0
- data/test/redirect_error.rb +16 -0
- data/test/rspec_integration/integration_spec.rb +6 -0
- data/test/test_demeter_mocking.rb +129 -0
- data/test/{test_mock.rb → test_deprecated_methods.rb} +64 -17
- data/test/test_example.rb +4 -3
- data/test/test_extended_should_receive.rb +1 -1
- data/test/test_flexmodel.rb +17 -1
- data/test/test_naming.rb +43 -8
- data/test/test_new_instances.rb +2 -22
- data/test/test_partial_mock.rb +19 -19
- data/test/test_record_mode.rb +27 -38
- data/test/test_should_receive.rb +199 -27
- metadata +11 -4
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
class FlexMock
|
4
|
+
module RedirectError
|
5
|
+
def redirect_error
|
6
|
+
require 'stringio'
|
7
|
+
old_err = $stderr
|
8
|
+
$stderr = StringIO.new
|
9
|
+
yield
|
10
|
+
$stderr.string
|
11
|
+
ensure
|
12
|
+
$stderr = old_err
|
13
|
+
end
|
14
|
+
private :redirect_error
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'flexmock'
|
5
|
+
require 'test/asserts'
|
6
|
+
|
7
|
+
class TestDemeterMocking < Test::Unit::TestCase
|
8
|
+
include FlexMock::TestCase
|
9
|
+
include FlexMock::FailureAssertion
|
10
|
+
|
11
|
+
def test_demeter_mocking
|
12
|
+
m = flexmock("A")
|
13
|
+
m.should_receive("children.first").and_return(:first)
|
14
|
+
assert_kind_of FlexMock, m
|
15
|
+
assert_kind_of FlexMock, m.children
|
16
|
+
assert_equal :first, m.children.first
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_multiple_demeter_mocks_on_same_branch_is_ok
|
20
|
+
m = flexmock("A")
|
21
|
+
m.should_receive("child.x.y.z.first").and_return(:first)
|
22
|
+
m.should_receive("child.x.y.z.last").and_return(:last)
|
23
|
+
assert_equal :first, m.child.x.y.z.first
|
24
|
+
assert_equal :last, m.child.x.y.z.last
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_multi_level_deep_demeter_violation
|
28
|
+
a = flexmock("a")
|
29
|
+
a.should_receive("b.c.d.e.f.g.h.i.j.k").and_return(:xyzzy)
|
30
|
+
assert_equal :xyzzy, a.b.c.d.e.f.g.h.i.j.k
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_final_method_can_have_multiple_expecations
|
34
|
+
a = flexmock("a")
|
35
|
+
a.should_receive("b.c.d.last").with(1).and_return(:one).once
|
36
|
+
a.should_receive("b.c.d.last").with(2).and_return(:two).once
|
37
|
+
assert_equal :one, a.b.c.d.last(1)
|
38
|
+
assert_equal :two, a.b.c.d.last(2)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_conflicting_mock_declarations_raises_an_error
|
42
|
+
m = flexmock("A")
|
43
|
+
ex = assert_raise(FlexMock::UsageError) do
|
44
|
+
m.should_receive("child").and_return(:xyzzy)
|
45
|
+
m.should_receive("child.other").and_return(:other)
|
46
|
+
m.child.other
|
47
|
+
end
|
48
|
+
assert_match(/conflicting/i, ex.message)
|
49
|
+
assert_match(/mock\s+declaration/i, ex.message)
|
50
|
+
assert_match(/child/i, ex.message)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_conflicting_mock_declarations_in_reverse_order_does_not_raise_error
|
54
|
+
# Not all conflicting definitions can be detected.
|
55
|
+
m = flexmock("A")
|
56
|
+
assert_failure() do
|
57
|
+
m.should_receive("child.other").and_return(:other)
|
58
|
+
m.should_receive("child").and_return(:xyzzy)
|
59
|
+
assert_equal :xyzzy, m.child.other
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_preestablishing_existing_mock_is_ok
|
64
|
+
engine = flexmock("engine")
|
65
|
+
car = flexmock("A")
|
66
|
+
car.should_receive(:engine).and_return(engine)
|
67
|
+
car.should_receive("engine.cylinder").and_return(:cyl)
|
68
|
+
assert_equal :cyl, car.engine.cylinder
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_quick_defs_can_use_demeter_mocking
|
72
|
+
a = flexmock("a")
|
73
|
+
a.should_receive("b.c.d.x").and_return(:x)
|
74
|
+
a.should_receive("b.c.d.y").and_return(:y)
|
75
|
+
a.should_receive("b.c.d.z").and_return(:z)
|
76
|
+
assert_equal :x, a.b.c.d.x
|
77
|
+
assert_equal :y, a.b.c.d.y
|
78
|
+
assert_equal :z, a.b.c.d.z
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_quick_defs_can_use_demeter_mocking_two
|
82
|
+
a = flexmock("a", "b.c.d.xx" => :x, "b.c.d.yy" => :y, "b.c.d.zz" => :z)
|
83
|
+
assert_equal :x, a.b.c.d.xx
|
84
|
+
assert_equal :y, a.b.c.d.yy
|
85
|
+
assert_equal :z, a.b.c.d.zz
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_errors_on_ill_formed_method_names
|
89
|
+
m = flexmock("a")
|
90
|
+
[
|
91
|
+
'a(2)', '0a', 'a-b', 'a b', ' ', 'a ', ' b', 'a!b', "a?b", 'a=b'
|
92
|
+
].each do |method|
|
93
|
+
assert_raise FlexMock::UsageError do m.should_receive(method) end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_no_errors_on_well_formed_method_names
|
98
|
+
m = flexmock("a")
|
99
|
+
[
|
100
|
+
'a', 'a?', 'a!', 'a=', 'z0', 'save!'
|
101
|
+
].each do |method|
|
102
|
+
assert_nothing_raised do m.should_receive(method) end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_readme_example_1
|
107
|
+
cog = flexmock("cog")
|
108
|
+
cog.should_receive(:turn).once.and_return(:ok).mock
|
109
|
+
joint = flexmock("gear", :cog => cog)
|
110
|
+
axle = flexmock("axle", :universal_joint => joint)
|
111
|
+
chassis = flexmock("chassis", :axle => axle)
|
112
|
+
car = flexmock("car", :chassis => chassis)
|
113
|
+
assert_equal :ok, car.chassis.axle.universal_joint.cog.turn
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_readme_example_2
|
117
|
+
car = flexmock("car")
|
118
|
+
car.should_receive("chassis.axle.universal_joint.cog.turn" => :ok).once
|
119
|
+
assert_equal :ok, car.chassis.axle.universal_joint.cog.turn
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_readme_example_3
|
123
|
+
car = flexmock("car")
|
124
|
+
car.should_receive("chassis.axle.universal_joint.cog.turn").once.
|
125
|
+
and_return(:ok)
|
126
|
+
assert_equal :ok, car.chassis.axle.universal_joint.cog.turn
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
@@ -11,34 +11,43 @@
|
|
11
11
|
|
12
12
|
require 'test/unit'
|
13
13
|
require 'flexmock'
|
14
|
+
require 'flexmock/deprecated_methods'
|
15
|
+
require 'test/redirect_error'
|
14
16
|
|
15
17
|
class TestFlexMock < Test::Unit::TestCase
|
18
|
+
include FlexMock::TestCase
|
19
|
+
include FlexMock::RedirectError
|
20
|
+
|
21
|
+
def s(&block)
|
22
|
+
redirect_error(&block)
|
23
|
+
end
|
24
|
+
|
16
25
|
def setup
|
17
|
-
@mock =
|
26
|
+
@mock = flexmock('mock')
|
18
27
|
end
|
19
28
|
|
20
29
|
def test_handle
|
21
30
|
args = nil
|
22
|
-
@mock.mock_handle(:hi) { |a, b| args = [a,b] }
|
31
|
+
s { @mock.mock_handle(:hi) { |a, b| args = [a,b] } }
|
23
32
|
@mock.hi(1,2)
|
24
33
|
assert_equal [1,2], args
|
25
34
|
end
|
26
35
|
|
27
36
|
def test_handle_no_block
|
28
|
-
@mock.mock_handle(:blip)
|
37
|
+
s { @mock.mock_handle(:blip) }
|
29
38
|
@mock.blip
|
30
39
|
assert true, "just checking for failures"
|
31
40
|
end
|
32
41
|
|
33
42
|
def test_called_with_block
|
34
43
|
called = false
|
35
|
-
@mock.mock_handle(:blip) { |block| block.call }
|
44
|
+
s { @mock.mock_handle(:blip) { |block| block.call } }
|
36
45
|
@mock.blip { called = true }
|
37
46
|
assert called, "Block to blip should be called"
|
38
47
|
end
|
39
48
|
|
40
49
|
def test_return_value
|
41
|
-
@mock.mock_handle(:blip) { 10 }
|
50
|
+
s { @mock.mock_handle(:blip) { 10 } }
|
42
51
|
assert_equal 10, @mock.blip
|
43
52
|
end
|
44
53
|
|
@@ -57,19 +66,19 @@ class TestFlexMock < Test::Unit::TestCase
|
|
57
66
|
end
|
58
67
|
|
59
68
|
def test_good_counts
|
60
|
-
@mock.mock_handle(:blip, 3)
|
69
|
+
s { @mock.mock_handle(:blip, 3) }
|
61
70
|
@mock.blip
|
62
71
|
@mock.blip
|
63
72
|
@mock.blip
|
64
|
-
@mock.
|
73
|
+
@mock.flexmock_verify
|
65
74
|
end
|
66
75
|
|
67
76
|
def test_bad_counts
|
68
|
-
@mock.mock_handle(:blip, 3)
|
77
|
+
s { @mock.mock_handle(:blip, 3) }
|
69
78
|
@mock.blip
|
70
79
|
@mock.blip
|
71
80
|
begin
|
72
|
-
@mock.
|
81
|
+
@mock.flexmock_verify
|
73
82
|
rescue Test::Unit::AssertionFailedError => err
|
74
83
|
end
|
75
84
|
assert_not_nil err
|
@@ -77,7 +86,7 @@ class TestFlexMock < Test::Unit::TestCase
|
|
77
86
|
|
78
87
|
def test_undetermined_counts
|
79
88
|
FlexMock.use('fs') { |m|
|
80
|
-
m.mock_handle(:blip)
|
89
|
+
s { m.mock_handle(:blip) }
|
81
90
|
m.blip
|
82
91
|
m.blip
|
83
92
|
m.blip
|
@@ -87,7 +96,7 @@ class TestFlexMock < Test::Unit::TestCase
|
|
87
96
|
def test_zero_counts
|
88
97
|
assert_raises(Test::Unit::AssertionFailedError) do
|
89
98
|
FlexMock.use { |m|
|
90
|
-
m.mock_handle(:blip, 0)
|
99
|
+
s { m.mock_handle(:blip, 0) }
|
91
100
|
m.blip
|
92
101
|
}
|
93
102
|
end
|
@@ -96,7 +105,7 @@ class TestFlexMock < Test::Unit::TestCase
|
|
96
105
|
def test_file_io_with_use
|
97
106
|
file = FlexMock.use do |m|
|
98
107
|
filedata = ["line 1", "line 2"]
|
99
|
-
m.mock_handle(:gets, 3) { filedata.shift }
|
108
|
+
s { m.mock_handle(:gets, 3) { filedata.shift } }
|
100
109
|
assert_equal 2, count_lines(m)
|
101
110
|
end
|
102
111
|
end
|
@@ -112,7 +121,7 @@ class TestFlexMock < Test::Unit::TestCase
|
|
112
121
|
def test_use
|
113
122
|
assert_raises(Test::Unit::AssertionFailedError) {
|
114
123
|
FlexMock.use do |m|
|
115
|
-
m.mock_handle(:blip, 2)
|
124
|
+
s { m.mock_handle(:blip, 2) }
|
116
125
|
m.blip
|
117
126
|
end
|
118
127
|
}
|
@@ -121,7 +130,7 @@ class TestFlexMock < Test::Unit::TestCase
|
|
121
130
|
def test_failures_during_use
|
122
131
|
ex = assert_raises(NameError) {
|
123
132
|
FlexMock.use do |m|
|
124
|
-
m.mock_handle(:blip, 2)
|
133
|
+
s { m.mock_handle(:blip, 2) }
|
125
134
|
xyz
|
126
135
|
end
|
127
136
|
}
|
@@ -130,7 +139,7 @@ class TestFlexMock < Test::Unit::TestCase
|
|
130
139
|
|
131
140
|
def test_sequential_values
|
132
141
|
values = [1,4,9,16]
|
133
|
-
@mock.mock_handle(:get) { values.shift }
|
142
|
+
s { @mock.mock_handle(:get) { values.shift } }
|
134
143
|
assert_equal 1, @mock.get
|
135
144
|
assert_equal 4, @mock.get
|
136
145
|
assert_equal 9, @mock.get
|
@@ -142,7 +151,7 @@ class TestFlexMock < Test::Unit::TestCase
|
|
142
151
|
end
|
143
152
|
|
144
153
|
def test_respond_to_returns_true_for_explicit_methods
|
145
|
-
@mock.mock_handle(:xyz)
|
154
|
+
s { @mock.mock_handle(:xyz) }
|
146
155
|
assert(@mock.respond_to?(:xyz), "should respond to test")
|
147
156
|
end
|
148
157
|
|
@@ -164,7 +173,7 @@ class TestFlexMock < Test::Unit::TestCase
|
|
164
173
|
|
165
174
|
def test_method_returns_callable_proc
|
166
175
|
got_it = false
|
167
|
-
@mock.mock_handle(:xyzzy) { got_it = true }
|
176
|
+
s { @mock.mock_handle(:xyzzy) { got_it = true } }
|
168
177
|
method_proc = @mock.method(:xyzzy)
|
169
178
|
assert_not_nil method_proc
|
170
179
|
method_proc.call
|
@@ -178,3 +187,41 @@ class TestFlexMock < Test::Unit::TestCase
|
|
178
187
|
method_proc.call
|
179
188
|
end
|
180
189
|
end
|
190
|
+
|
191
|
+
class TestDeprecatedOrderingMethods < Test::Unit::TestCase
|
192
|
+
include FlexMock::TestCase
|
193
|
+
include FlexMock::RedirectError
|
194
|
+
|
195
|
+
def test_deprecated_ordering_methods
|
196
|
+
flexmock(:x).should_receive(:msg).globally.ordered(:testgroup)
|
197
|
+
assert_equal({ :testgroup => 1 }, flexmock_groups)
|
198
|
+
message = redirect_error do
|
199
|
+
assert_equal({ :testgroup => 1 }, mock_groups)
|
200
|
+
end
|
201
|
+
assert_match(/deprecated/i, message)
|
202
|
+
assert_match(/\bmock_groups/, message)
|
203
|
+
assert_match(/\bflexmock_groups/, message)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
class TestAnyInstance < Test::Unit::TestCase
|
208
|
+
include FlexMock::TestCase
|
209
|
+
include FlexMock::RedirectError
|
210
|
+
|
211
|
+
class Dog
|
212
|
+
def bark
|
213
|
+
:woof
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_any_instance_still_works_for_backwards_compatibility
|
218
|
+
message = redirect_error do
|
219
|
+
flexstub(Dog).any_instance do |obj|
|
220
|
+
obj.should_receive(:bark).and_return(:whimper)
|
221
|
+
assert_match(/deprecated/, message)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
m = Dog.new
|
225
|
+
assert_equal :whimper, m.bark
|
226
|
+
end
|
227
|
+
end
|
data/test/test_example.rb
CHANGED
@@ -21,14 +21,15 @@ class TemperatureSampler
|
|
21
21
|
total = (0...3).collect { @sensor.read_temperature }.inject { |i, s| i + s }
|
22
22
|
total / 3.0
|
23
23
|
end
|
24
|
-
|
25
24
|
end
|
26
25
|
|
27
26
|
class TestTemperatureSampler < Test::Unit::TestCase
|
27
|
+
include FlexMock::TestCase
|
28
|
+
|
28
29
|
def test_tempurature_sampler
|
29
30
|
readings = [10, 12, 14]
|
30
|
-
mock_sensor =
|
31
|
-
mock_sensor.
|
31
|
+
mock_sensor = flexmock("sensor")
|
32
|
+
mock_sensor.should_receive(:read_temperature).and_return { readings.shift }
|
32
33
|
sampler = TemperatureSampler.new(mock_sensor)
|
33
34
|
assert_equal 12, sampler.average_temp
|
34
35
|
end
|
@@ -36,7 +36,7 @@ module ExtendedShouldReceiveTests
|
|
36
36
|
def test_count_contraints_apply_to_all_expectations
|
37
37
|
@mock.should_receive(:foo, :bar => :baz).once
|
38
38
|
@obj.foo
|
39
|
-
assert_raise(Test::Unit::AssertionFailedError) { @mock.
|
39
|
+
assert_raise(Test::Unit::AssertionFailedError) { @mock.flexmock_verify }
|
40
40
|
end
|
41
41
|
|
42
42
|
def test_multiple_should_receives_are_allowed
|
data/test/test_flexmodel.rb
CHANGED
@@ -5,17 +5,33 @@ require 'test/unit'
|
|
5
5
|
class DummyModel
|
6
6
|
end
|
7
7
|
|
8
|
+
class ChildModel < DummyModel
|
9
|
+
end
|
10
|
+
|
8
11
|
######################################################################
|
9
12
|
class TestFlexModel < Test::Unit::TestCase
|
10
13
|
include FlexMock::TestCase
|
11
14
|
|
12
15
|
def test_initial_conditions
|
13
16
|
model = flexmock(:model, DummyModel)
|
14
|
-
assert_match(/^DummyModel_\d+/, model.
|
17
|
+
assert_match(/^DummyModel_\d+/, model.flexmock_name)
|
15
18
|
assert_equal model.id.to_s, model.to_params
|
16
19
|
assert ! model.new_record?
|
17
20
|
assert model.is_a?(DummyModel)
|
21
|
+
# TODO: Make these work!!!
|
18
22
|
assert_equal DummyModel, model.class
|
23
|
+
assert model.instance_of?(DummyModel)
|
24
|
+
assert model.kind_of?(DummyModel)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_classifying_mock_models
|
28
|
+
model = flexmock(:model, ChildModel)
|
29
|
+
|
30
|
+
assert model.kind_of?(ChildModel)
|
31
|
+
assert model.instance_of?(ChildModel)
|
32
|
+
|
33
|
+
assert model.kind_of?(DummyModel)
|
34
|
+
assert ! model.instance_of?(DummyModel)
|
19
35
|
end
|
20
36
|
|
21
37
|
def test_mock_models_have_different_ids
|
data/test/test_naming.rb
CHANGED
@@ -13,13 +13,15 @@ require 'test/unit'
|
|
13
13
|
require 'flexmock'
|
14
14
|
|
15
15
|
class TestNaming < Test::Unit::TestCase
|
16
|
+
include FlexMock::TestCase
|
17
|
+
|
16
18
|
def test_name
|
17
|
-
m =
|
18
|
-
assert_equal "m", m.
|
19
|
+
m = flexmock("m")
|
20
|
+
assert_equal "m", m.flexmock_name
|
19
21
|
end
|
20
22
|
|
21
23
|
def test_name_in_no_handler_found_error
|
22
|
-
m =
|
24
|
+
m = flexmock("mmm")
|
23
25
|
ex = assert_raises(Test::Unit::AssertionFailedError) {
|
24
26
|
m.should_receive(:xx).with(1)
|
25
27
|
m.xx(2)
|
@@ -28,24 +30,57 @@ class TestNaming < Test::Unit::TestCase
|
|
28
30
|
end
|
29
31
|
|
30
32
|
def test_name_in_received_count_error
|
31
|
-
m =
|
33
|
+
m = flexmock("mmm")
|
32
34
|
ex = assert_raises(Test::Unit::AssertionFailedError) {
|
33
35
|
m.should_receive(:xx).once
|
34
|
-
m.
|
36
|
+
m.flexmock_verify
|
35
37
|
}
|
36
38
|
assert_match(/'mmm'/, ex.message)
|
37
39
|
end
|
38
40
|
|
39
41
|
def test_naming_with_use
|
40
42
|
FlexMock.use("blah") do |m|
|
41
|
-
assert_equal "blah", m.
|
43
|
+
assert_equal "blah", m.flexmock_name
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
45
47
|
def test_naming_with_multiple_mocks_in_use
|
46
48
|
FlexMock.use("blah", "yuk") do |a, b|
|
47
|
-
assert_equal "blah", a.
|
48
|
-
assert_equal "yuk", b.
|
49
|
+
assert_equal "blah", a.flexmock_name
|
50
|
+
assert_equal "yuk", b.flexmock_name
|
49
51
|
end
|
50
52
|
end
|
53
|
+
|
54
|
+
def test_inspect_returns_reasonable_name
|
55
|
+
FlexMock.use("XYZZY") do |m|
|
56
|
+
assert_equal "XYZZY", m.flexmock_name
|
57
|
+
assert_equal "<FlexMock:XYZZY>", m.inspect
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_mock_can_override_inspect
|
62
|
+
FlexMock.use("XYZZY") do |m|
|
63
|
+
m.should_receive(:inspect).with_no_args.and_return("MOCK-INSPECT")
|
64
|
+
assert_equal "MOCK-INSPECT", m.inspect
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Dummy
|
69
|
+
def inspect
|
70
|
+
"DUMMY-INSPECT"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_partial_mocks_use_original_inspect
|
75
|
+
dummy = Dummy.new
|
76
|
+
flexmock(dummy).should_receive(:msg)
|
77
|
+
assert_equal "DUMMY-INSPECT", dummy.inspect
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_partial_mocks_can_override_inspect
|
81
|
+
dummy = Dummy.new
|
82
|
+
flexmock(dummy).should_receive(:inspect).and_return("MOCK-INSPECT")
|
83
|
+
assert_equal "MOCK-INSPECT", dummy.inspect
|
84
|
+
end
|
51
85
|
end
|
86
|
+
|