derickbailey-notamock 0.0.1

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.
@@ -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