derickbailey-notamock 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,26 @@
1
+ require 'singleton'
2
+
3
+ module NotAMock
4
+ class StubMethod
5
+ def initialize(&block)
6
+ @block = block
7
+ @yield_values = []
8
+ end
9
+
10
+ def yields(*args, &block)
11
+ @yield_values = args
12
+ (@block = block) unless block.nil?
13
+ end
14
+
15
+ def execute_return_block(*args)
16
+ return_value = nil
17
+ (return_value = @block.call(*args)) unless @block.nil?
18
+ return_value
19
+ end
20
+
21
+ def yield_to_block(&block)
22
+ return if block.nil?
23
+ block.call(*@yield_values)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,68 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
+ require 'not_a_mock'
3
+
4
+ class TrackedClass
5
+ def my_method(argument)
6
+ "result"
7
+ end
8
+ end
9
+
10
+ describe "A recorded method" do
11
+
12
+ before do
13
+ @recorder = NotAMock::CallRecorder.instance
14
+ @object = TrackedClass.new
15
+ @object.track_method(:my_method)
16
+ end
17
+
18
+ it "should record a method call" do
19
+ @object.my_method("argument")
20
+
21
+ @recorder.calls.should include(:object => @object, :method => :my_method, :args => ["argument"], :result => "result")
22
+ end
23
+
24
+ it "should not record calls after untrack_method" do
25
+ @object.my_method("argument 1")
26
+ @object.untrack_method(:my_method)
27
+ @object.my_method("argument 2")
28
+
29
+ @recorder.calls.should include(:object => @object, :method => :my_method, :args => ["argument 1"], :result => "result")
30
+ @recorder.calls.should_not include(:object => @object, :method => :my_method, :args => ["argument 2"], :result => "result")
31
+ end
32
+
33
+ it "should not record calls after stop_all_recording" do
34
+ @object.track_method(:my_method)
35
+ @object.my_method("argument 1")
36
+ @recorder.untrack_all
37
+ @object.my_method("argument 2")
38
+
39
+ @recorder.calls.should include(:object => @object, :method => :my_method, :args => ["argument 1"], :result => "result")
40
+ @recorder.calls.should_not include(:object => @object, :method => :my_method, :args => ["argument 2"], :result => "result")
41
+ end
42
+
43
+ it "should not break when track_method is called again" do
44
+ @object.track_method(:my_method)
45
+ @object.my_method("argument 1")
46
+ @object.untrack_method(:my_method)
47
+ @object.my_method("argument 2")
48
+
49
+ @recorder.calls.should include(:object => @object, :method => :my_method, :args => ["argument 1"], :result => "result")
50
+ @recorder.calls.should_not include(:object => @object, :method => :my_method, :args => ["argument 2"], :result => "result")
51
+ end
52
+
53
+ it "should not break when untrack_method is called more than once" do
54
+ @object.track_method(:my_method)
55
+ @object.my_method("argument 1")
56
+ @object.untrack_method(:my_method)
57
+ @object.untrack_method(:my_method)
58
+ @object.my_method("argument 2")
59
+
60
+ @recorder.calls.should include(:object => @object, :method => :my_method, :args => ["argument 1"], :result => "result")
61
+ @recorder.calls.should_not include(:object => @object, :method => :my_method, :args => ["argument 2"], :result => "result")
62
+ end
63
+
64
+ after do
65
+ @recorder.reset
66
+ end
67
+
68
+ end
@@ -0,0 +1,217 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
+ require 'not_a_mock'
3
+
4
+ class TrackedClass < Object
5
+ def initialize(*calls)
6
+ calls.each do |call|
7
+ NotAMock::CallRecorder.instance.calls << call.merge(:object => self)
8
+ end
9
+ end
10
+
11
+ def inspect
12
+ "TrackedClass"
13
+ end
14
+ end
15
+
16
+ describe NotAMock::Matchers::AnythingMatcher do
17
+
18
+ it "should match if a method was called" do
19
+ @object = TrackedClass.new({ :method => :length, :args => [], :result => nil })
20
+ @matcher = have_been_called
21
+ @matcher.matches?(@object).should be_true
22
+ @matcher.negative_failure_message.should == "TrackedClass was called"
23
+ end
24
+
25
+ it "should not match if a method wasn't called" do
26
+ @object = TrackedClass.new
27
+ @matcher = have_been_called
28
+ @matcher.matches?(@object).should be_false
29
+ @matcher.failure_message.should == "TrackedClass was never called"
30
+ end
31
+
32
+ after do
33
+ NotAMock::CallRecorder.instance.reset
34
+ end
35
+
36
+ end
37
+
38
+ describe NotAMock::Matchers::MethodMatcher do
39
+
40
+ it "should match a called method" do
41
+ @object = TrackedClass.new({ :method => :length, :args => [], :result => nil })
42
+ @matcher = have_received(:length)
43
+ @matcher.matches?(@object).should be_true
44
+ @matcher.negative_failure_message.should == "TrackedClass received length"
45
+ end
46
+
47
+ it "should not match an uncalled method" do
48
+ @object = TrackedClass.new
49
+ @matcher = have_received(:width)
50
+ @matcher.matches?(@object).should be_false
51
+ @matcher.failure_message.should == "TrackedClass didn't receive width"
52
+ end
53
+
54
+ after do
55
+ NotAMock::CallRecorder.instance.reset
56
+ end
57
+
58
+ end
59
+
60
+ describe NotAMock::Matchers::ArgsMatcher, "matching calls with arguments " do
61
+
62
+ before do
63
+ @object = TrackedClass.new({ :method => :length, :args => [1, [2, 3, 4], 5], :result => nil })
64
+ end
65
+
66
+ it "should match a called method with the correct arguments" do
67
+ @matcher = have_received(:length).with(1, [2, 3, 4], 5)
68
+ @matcher.matches?(@object).should be_true
69
+ @matcher.negative_failure_message.should == "TrackedClass received length, with args [1, [2, 3, 4], 5]"
70
+ end
71
+
72
+ it "should not match a called method with the wrong arguments" do
73
+ @matcher = have_received(:length).with(3, 2, 1)
74
+ @matcher.matches?(@object).should be_false
75
+ @matcher.failure_message.should == "TrackedClass received length, but not with args [3, 2, 1]"
76
+ end
77
+
78
+ it "should match a called method with a wildcard argument" do
79
+ @matcher = have_received(:length).with(1, anything, 5)
80
+ @matcher.matches?(@object).should be_true
81
+ @matcher.matches?(@object).should be_true
82
+ @matcher.negative_failure_message.should == "TrackedClass received length, with args [1, anything, 5]"
83
+ end
84
+
85
+ it "should match a called method with a wildcard argument" do
86
+ @matcher = have_received(:length).with(1, in_any_order([4, 3, 2]), 5)
87
+ @matcher.matches?(@object).should be_true
88
+ @matcher.matches?(@object).should be_true
89
+ @matcher.negative_failure_message.should == "TrackedClass received length, with args [1, in_any_order([4, 3, 2]), 5]"
90
+ end
91
+
92
+ after do
93
+ NotAMock::CallRecorder.instance.reset
94
+ end
95
+
96
+ end
97
+
98
+ describe NotAMock::Matchers::ArgsMatcher, "matching calls without arguments" do
99
+
100
+ before do
101
+ @object = TrackedClass.new(
102
+ { :method => :length, :args => [1, 2, 3], :result => nil },
103
+ { :method => :width, :args => [], :result => nil }
104
+ )
105
+ end
106
+
107
+ it "should match a method called without arguments" do
108
+ @matcher = have_received(:width).without_args
109
+ @matcher.matches?(@object).should be_true
110
+ @matcher.negative_failure_message.should == "TrackedClass received width, without args"
111
+ end
112
+
113
+ it "should not match a method called with arguments" do
114
+ @matcher = have_received(:length).without_args
115
+ @matcher.matches?(@object).should be_false
116
+ @matcher.failure_message.should == "TrackedClass received length, but not without args"
117
+ end
118
+
119
+ after do
120
+ NotAMock::CallRecorder.instance.reset
121
+ end
122
+
123
+ end
124
+
125
+ describe NotAMock::Matchers::ResultMatcher do
126
+
127
+ before do
128
+ @object = TrackedClass.new(
129
+ { :method => :length, :args => [], :result => 13 },
130
+ { :method => :width, :args => [], :result => 42 }
131
+ )
132
+ end
133
+
134
+ it "should match a method that returned the correct result" do
135
+ @matcher = have_received(:length).and_returned(13)
136
+ @matcher.matches?(@object).should be_true
137
+ @matcher.negative_failure_message.should == "TrackedClass received length, and returned 13"
138
+ end
139
+
140
+ it "should not match a method the returned the wrong result" do
141
+ @matcher = have_received(:width).and_returned(13)
142
+ @matcher.matches?(@object).should be_false
143
+ @matcher.failure_message.should == "TrackedClass received width, but didn't return 13"
144
+ end
145
+
146
+ after do
147
+ NotAMock::CallRecorder.instance.reset
148
+ end
149
+
150
+ end
151
+
152
+ describe NotAMock::Matchers::TimesMatcher do
153
+
154
+ before do
155
+ @object = TrackedClass.new(
156
+ { :method => :once, :args => [], :result => nil },
157
+ { :method => :twice, :args => [], :result => nil },
158
+ { :method => :twice, :args => [], :result => nil },
159
+ { :method => :thrice, :args => [], :result => nil },
160
+ { :method => :thrice, :args => [], :result => nil },
161
+ { :method => :thrice, :args => [], :result => nil }
162
+ )
163
+ end
164
+
165
+ it "should match a method that was called once" do
166
+ @matcher = have_received(:once).once
167
+ @matcher.matches?(@object).should be_true
168
+ @matcher.negative_failure_message.should == "TrackedClass received once, once"
169
+ end
170
+
171
+ it "should match a method that was called twice" do
172
+ @matcher = have_received(:twice).twice
173
+ @matcher.matches?(@object).should be_true
174
+ @matcher.negative_failure_message.should == "TrackedClass received twice, twice"
175
+ end
176
+
177
+ it "should match a method that was called 3 times" do
178
+ @matcher = have_received(:thrice).exactly(3).times
179
+ @matcher.matches?(@object).should be_true
180
+ @matcher.negative_failure_message.should == "TrackedClass received thrice, 3 times"
181
+ end
182
+
183
+ it "should not match a method a method that was called the wrong number of times" do
184
+ @matcher = have_received(:thrice).once
185
+ @matcher.matches?(@object).should be_false
186
+ @matcher.failure_message.should == "TrackedClass received thrice, but 3 times"
187
+ end
188
+
189
+ after do
190
+ NotAMock::CallRecorder.instance.reset
191
+ end
192
+
193
+ end
194
+
195
+ describe "A chain of matchers" do
196
+
197
+ before do
198
+ @object = TrackedClass.new({ :method => :length, :args => [1, 2, 3], :result => 42 })
199
+ end
200
+
201
+ it "should match the correct method, args, and result" do
202
+ @matcher = have_received(:length).with(1, 2, 3).and_returned(42)
203
+ @matcher.matches?(@object).should be_true
204
+ @matcher.negative_failure_message.should == "TrackedClass received length, with args [1, 2, 3], and returned 42"
205
+ end
206
+
207
+ it "should not match the correct method, but with the incorrect args" do
208
+ @matcher = have_received(:length).with(3, 2, 1).and_returned(42)
209
+ @matcher.matches?(@object).should be_false
210
+ @matcher.failure_message.should == "TrackedClass received length, but not with args [3, 2, 1]"
211
+ end
212
+
213
+ after do
214
+ NotAMock::CallRecorder.instance.reset
215
+ end
216
+
217
+ end
@@ -0,0 +1,29 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
+ require 'not_a_mock'
3
+
4
+ class ExampleActiveRecord < ActiveRecord::Base
5
+ end
6
+
7
+ describe "A stubbed ActiveRecord object" do
8
+
9
+ before do
10
+ @example = ExampleActiveRecord.stub_instance
11
+ end
12
+
13
+ it "should return a valid id" do
14
+ lambda { @example.id }.should_not raise_error(NoMethodError)
15
+ @example.id.should be_an_instance_of(Fixnum)
16
+ end
17
+
18
+ it "should return the id as a string for to_param" do
19
+ lambda { @example.to_param }.should_not raise_error(NoMethodError)
20
+ @example.to_param.should be_an_instance_of(String)
21
+ @example.to_param.should == @example.id.to_s
22
+ end
23
+
24
+ after do
25
+ NotAMock::CallRecorder.instance.reset
26
+ NotAMock::Stubber.instance.reset
27
+ end
28
+
29
+ end
@@ -0,0 +1,49 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
+ require 'not_a_mock'
3
+
4
+ describe "A stub instance" do
5
+
6
+ before do
7
+ @object = String.stub_instance(:length => 42, :id => 99)
8
+ end
9
+
10
+ it "should return the right result for a stubbed method" do
11
+ @object.length.should == 42
12
+ end
13
+
14
+ it "should return its name when inspected" do
15
+ @object.inspect.should == "Stub String"
16
+ end
17
+
18
+ it "should handle the id method being stubbed" do
19
+ @object.id.should == 99
20
+ end
21
+
22
+ it "should raise an error when a method that's not stubbed is called" do
23
+ lambda { @object.whatever }.should raise_error(NoMethodError)
24
+ end
25
+
26
+ it "should record a call to a stubbed method" do
27
+ @object.length
28
+ NotAMock::CallRecorder.instance.calls.should include(:object => @object, :method => :length, :args => [], :result => 42)
29
+ end
30
+
31
+ it "should allow adding of new stubbed methods" do
32
+ @object.stub_method(:width => 7)
33
+ @object.width.should == 7
34
+ end
35
+
36
+ it "should identify itself as the underlying object" do
37
+ @object.is_a?(String).should be_true
38
+ @object.should be_kind_of(String)
39
+ @object.should be_kind_of(Object)
40
+ @object.should be_instance_of(String)
41
+ @object.class.should == String
42
+ end
43
+
44
+ after do
45
+ NotAMock::CallRecorder.instance.reset
46
+ NotAMock::Stubber.instance.reset
47
+ end
48
+
49
+ end
@@ -0,0 +1,242 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
+ require 'not_a_mock'
3
+
4
+ describe "A stubbed method replacing an existing instance method" do
5
+
6
+ before do
7
+ @object = "Hello, world!"
8
+ @object.stub_method(:length => 42)
9
+ end
10
+
11
+ it "should return the stubbed result" do
12
+ @object.length.should == 42
13
+ end
14
+
15
+ it "should return the original result after stubbing is removed" do
16
+ @object.unstub_method(:length)
17
+ @object.length.should == 13
18
+ end
19
+
20
+ it "should return the original result after a reset" do
21
+ NotAMock::Stubber.instance.reset
22
+ @object.length.should == 13
23
+ end
24
+
25
+ it "should return the new result if re-stubbed" do
26
+ @object.stub_method(:length => 24)
27
+ @object.length.should == 24
28
+ end
29
+
30
+ it "should record a call to the stubbed method" do
31
+ @object.length
32
+ NotAMock::CallRecorder.instance.calls.should include(:object => @object, :method => :length, :args => [], :result => 42)
33
+ end
34
+
35
+ it "should return a call to the stubbed method if re-stubbed" do
36
+ @object.stub_method(:length => 24)
37
+ @object.length
38
+ NotAMock::CallRecorder.instance.calls.should include(:object => @object, :method => :length, :args => [], :result => 24)
39
+ end
40
+
41
+ after do
42
+ NotAMock::CallRecorder.instance.reset
43
+ NotAMock::Stubber.instance.reset
44
+ end
45
+
46
+ end
47
+
48
+ describe "A stubbed method with no existing instance method" do
49
+
50
+ before do
51
+ @object = "Hello, world!"
52
+ @object.stub_method(:blah => 42)
53
+ end
54
+
55
+ it "should return the stubbed result" do
56
+ @object.blah.should == 42
57
+ end
58
+
59
+ it "should raise a NoMethodError when the method is called after stubbing is removed" do
60
+ @object.unstub_method(:blah)
61
+ lambda { @object.blah }.should raise_error(NoMethodError)
62
+ end
63
+
64
+ it "should raise a NoMethodError when the method is called after all stubbing is removed" do
65
+ NotAMock::Stubber.instance.reset
66
+ lambda { @object.blah }.should raise_error(NoMethodError)
67
+ end
68
+
69
+ it "should record a call to the stubbed method" do
70
+ @object.blah
71
+ NotAMock::CallRecorder.instance.calls.should include(:object => @object, :method => :blah, :args => [], :result => 42)
72
+ end
73
+
74
+ after do
75
+ NotAMock::CallRecorder.instance.reset
76
+ NotAMock::Stubber.instance.reset
77
+ end
78
+
79
+ end
80
+
81
+ describe "A stubbed class method" do
82
+
83
+ before do
84
+ Time.stub_method(:now => 42)
85
+ end
86
+
87
+ it "should return the stubbed result" do
88
+ Time.now.should == 42
89
+ end
90
+
91
+ it "should return the original result after stubbing is removed" do
92
+ Time.unstub_method(:now)
93
+ Time.now.should_not == 42
94
+ end
95
+
96
+ it "should return the original result after a reset" do
97
+ NotAMock::Stubber.instance.reset
98
+ Time.now.should_not == 42
99
+ end
100
+
101
+ after do
102
+ NotAMock::CallRecorder.instance.reset
103
+ NotAMock::Stubber.instance.reset
104
+ end
105
+
106
+ end
107
+
108
+ describe "A stubbed private method" do
109
+ before do
110
+ class Privateer
111
+ private
112
+
113
+ def self.stubbed
114
+ false
115
+ end
116
+ end
117
+
118
+ Privateer.stub_method(:stubbed => true)
119
+ end
120
+
121
+ it "should return the stubbed result" do
122
+ Privateer.send(:stubbed).should be_true
123
+ end
124
+
125
+ it "should return the original result after stubbing is removed" do
126
+ Privateer.unstub_method(:stubbed)
127
+ Privateer.send(:stubbed).should be_false
128
+ end
129
+
130
+ it "should return the original result after a reset" do
131
+ NotAMock::Stubber.instance.reset
132
+ Privateer.send(:stubbed).should be_false
133
+ end
134
+
135
+ after do
136
+ NotAMock::CallRecorder.instance.reset
137
+ NotAMock::Stubber.instance.reset
138
+ end
139
+ end
140
+
141
+ describe "A stubbed protected method" do
142
+ before :each do
143
+ class Protector
144
+ protected
145
+
146
+ def self.stubbed
147
+ false
148
+ end
149
+ end
150
+
151
+ Protector.stub_method(:stubbed => true)
152
+ end
153
+
154
+ it "should return the stubbed result" do
155
+ Protector.send(:stubbed).should be_true
156
+ end
157
+
158
+ it "should return the original result after stubbing is removed" do
159
+ Protector.unstub_method(:stubbed)
160
+ Protector.send(:stubbed).should be_false
161
+ end
162
+
163
+ it "should return the original result after a reset" do
164
+ NotAMock::Stubber.instance.reset
165
+ Protector.send(:stubbed).should be_false
166
+ end
167
+
168
+ after do
169
+ NotAMock::CallRecorder.instance.reset
170
+ NotAMock::Stubber.instance.reset
171
+ end
172
+ end
173
+
174
+ describe "A method stubbed with a block" do
175
+
176
+ before do
177
+ @object = "Hello, world!"
178
+ @object.stub_method(:length) do |*args|
179
+ args.reverse
180
+ end
181
+ end
182
+
183
+ it "should return the result of the block" do
184
+ @object.length(1, 2, 3).should == [3, 2, 1]
185
+ end
186
+
187
+ after do
188
+ NotAMock::CallRecorder.instance.reset
189
+ NotAMock::Stubber.instance.reset
190
+ end
191
+
192
+ end
193
+
194
+ describe "A method stubbed to raise an exception" do
195
+
196
+ before do
197
+ @object = "Hello, world!"
198
+ @object.stub_method_to_raise(:length => ArgumentError)
199
+ end
200
+
201
+ it "should raise the exception when called" do
202
+ lambda { @object.length }.should raise_error(ArgumentError)
203
+ end
204
+
205
+ it "should return the original result after stubbing is removed" do
206
+ @object.unstub_method(:length)
207
+ @object.length.should == 13
208
+ end
209
+
210
+ after do
211
+ NotAMock::CallRecorder.instance.reset
212
+ NotAMock::Stubber.instance.reset
213
+ end
214
+
215
+ end
216
+
217
+ describe "Object#stub_method" do
218
+
219
+ it "should stub a method with a name ending in '?'" do
220
+ @object = "Hello, world!"
221
+ @object.stub_method(:is_great? => true)
222
+ @object.is_great?.should be_true
223
+ end
224
+
225
+ it "should stub the []= method" do
226
+ @object = Array.new
227
+ @object.stub_method(:[]= => nil)
228
+ @object[0] = 7
229
+ @object.length.should == 0
230
+ end
231
+
232
+ it "should raise an ArgumentError if called with something other than a symbol or hash" do
233
+ @object = "Hello, world!"
234
+ lambda { @object.stub_method(7) }.should raise_error(ArgumentError)
235
+ end
236
+
237
+ after do
238
+ NotAMock::CallRecorder.instance.reset
239
+ NotAMock::Stubber.instance.reset
240
+ end
241
+
242
+ end