fakes 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/Guardfile +5 -0
- data/README.md +229 -0
- data/Rakefile +1 -0
- data/fakes.gemspec +27 -0
- data/lib/fakes.rb +12 -0
- data/lib/fakes/arg_behaviour.rb +22 -0
- data/lib/fakes/arg_set.rb +10 -0
- data/lib/fakes/fake.rb +29 -0
- data/lib/fakes/ignore_set.rb +24 -0
- data/lib/fakes/method_stub.rb +45 -0
- data/lib/fakes/version.rb +3 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/specs/arg_behaviour_spec.rb +67 -0
- data/spec/specs/arg_set_spec.rb +13 -0
- data/spec/specs/fake_spec.rb +220 -0
- data/spec/specs/ignore_set_spec.rb +41 -0
- data/spec/specs/kernel_spec.rb +6 -0
- data/spec/specs/method_stub_spec.rb +167 -0
- metadata +154 -0
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.3@developwithpassion_fakes --create
|
data/Gemfile
ADDED
data/Guardfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
#fakes
|
2
|
+
|
3
|
+
This is a really simple library to aid in AAA style testing. The primary driver for using this is to be able to make assertions on method calls to collaborators in actual assertions and not as part of setup. It is meant to be used to complement the current testing framework that you are using to aid in the creation of interaction based tests.
|
4
|
+
|
5
|
+
Here is a simple example
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
class SomeClass
|
9
|
+
def initialize(collaborator)
|
10
|
+
@collaborator = collaborator
|
11
|
+
end
|
12
|
+
def run()
|
13
|
+
@collaborator.send_message("Hi")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe SomeClass do
|
18
|
+
context "when run" do
|
19
|
+
let(:collaborator){fake}
|
20
|
+
let(:sut){SomeClass.new(collaborator)}
|
21
|
+
|
22
|
+
before(:each) do
|
23
|
+
sut.run
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should trigger its collaborator with the correct message" do
|
27
|
+
collaborator.received(:send_message).called_with("Hi").should_not be_nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
##Creating a new fake
|
34
|
+
|
35
|
+
To create a new fake, simply leverage the fake method that is mixed into the Kernel module.
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
require 'fakes'
|
39
|
+
|
40
|
+
item = fake
|
41
|
+
```
|
42
|
+
|
43
|
+
##Specifying the behaviour of a fake
|
44
|
+
|
45
|
+
When scaffolding fake return values, the library behaves almost identically to the way RSpec stubs work.
|
46
|
+
|
47
|
+
###Setup a method to return a value for a particular set of arguments
|
48
|
+
```ruby
|
49
|
+
collaborator = fake
|
50
|
+
|
51
|
+
collaborator.stub(:name_of_method).with(arg1,arg2,arg3).and_return(return_value)
|
52
|
+
```
|
53
|
+
|
54
|
+
###Setup a method to return a value regardless of the arguments it is called with
|
55
|
+
```ruby
|
56
|
+
collaborator = fake
|
57
|
+
|
58
|
+
#long handed way
|
59
|
+
collaborator.stub(:name_of_method).ignore_arg.and_return(return_value)
|
60
|
+
|
61
|
+
#preferred way
|
62
|
+
collaborator.stub(:name_of_method).and_return(return_value)
|
63
|
+
```
|
64
|
+
|
65
|
+
###Setup different return values for different argument sets
|
66
|
+
```ruby
|
67
|
+
collaborator = fake
|
68
|
+
|
69
|
+
#Setup a return value for 1
|
70
|
+
collaborator.stub(:method).with(1).and_return(first_return_value)
|
71
|
+
|
72
|
+
#Setup a return value for 2
|
73
|
+
collaborator.stub(:method).with(2).and_return(second_return_value)
|
74
|
+
|
75
|
+
#Setup a return value when called with everything else
|
76
|
+
#if you are going to use this, make sure it is used after
|
77
|
+
#setting up return values for specific arguments
|
78
|
+
collaborator.stub(:method).and_return(value_to_return_with_arguments_other_than_1_and_2)
|
79
|
+
```
|
80
|
+
|
81
|
+
##Verifying calls made to the fake
|
82
|
+
|
83
|
+
|
84
|
+
###Verifying when a call was made
|
85
|
+
|
86
|
+
The primary purpose of the library is to help you in doing interaction style testing in a AAA style. Assume the following class is one you would like to test:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
class ItemToTest
|
90
|
+
def initialize(collaborator)
|
91
|
+
@collaborator = collaborator
|
92
|
+
end
|
93
|
+
|
94
|
+
def run
|
95
|
+
@collaborator.send_message("Hello World")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
ItemToTest is supposed to leverage its collaborator and calls its send_message method with the argument "Hello World". To verify this using AAA style, interaction testing you can do the following (I am using rspec, but you can use this with any testing library you wish):
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
describe ItemToTest do
|
104
|
+
context "when run" do
|
105
|
+
let(:collaborator){fake}
|
106
|
+
let(:sut){ItemToTest.new(collaborator)}
|
107
|
+
|
108
|
+
#I typically use a before block to specifically trigger the method that I am testing, so it cleanly
|
109
|
+
#separates it from the assertions I will make later
|
110
|
+
before(:each) do
|
111
|
+
sut.run
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should trigger its collaborator with the correct message" do
|
115
|
+
collaborator.received(:send_message).called_with("Hello World").should_not be_nil
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
```
|
120
|
+
From the example above, you can see that we created the fake and did not need to scaffold it with any behaviour.
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
let(:collaborator){fake}
|
124
|
+
```
|
125
|
+
|
126
|
+
You can also see that we are create our System Under Test (sut) and provide it the collaborator:
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
let(:sut){ItemToTest.new(collaborator)}
|
130
|
+
```
|
131
|
+
|
132
|
+
We then proceed to invoke the method on the component we are testing
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
before(:each) do
|
136
|
+
sut.run
|
137
|
+
end
|
138
|
+
```
|
139
|
+
|
140
|
+
Last but not least, we verify that our collaborator was invoked and with the right arguments:
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
it "should trigger its collaborator with the correct message" do
|
144
|
+
collaborator.received(:send_message).called_with("Hello World").should_not be_nil
|
145
|
+
end
|
146
|
+
```
|
147
|
+
|
148
|
+
The nice thing is we can make the assertions after the fact, as opposed to needing to do them as part of setup, which I find is a much more natural way to read things, when you need to do this style of test. Notice that the called_with method return a method_invocation that will be nil if the call was not received. My recommendation would be to create a test utility method that allows you to leverage your testing frameworks assertion library to make the above assertion more terse. The
|
149
|
+
following rspec sample demonstrates:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
module RSpec
|
153
|
+
Matchers.define :have_received do|symbol,*args|
|
154
|
+
match do|fake|
|
155
|
+
fake.received(symbol).called_with(*args) != nil
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
```
|
160
|
+
|
161
|
+
Using the above utility method turns the previous assertion:
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
collaborator.received(:send_message).called_with("Hello World").should_not be_nil
|
165
|
+
```
|
166
|
+
|
167
|
+
To this:
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
collaborator.should have_received(:send_message,"Hello World")
|
171
|
+
```
|
172
|
+
|
173
|
+
###Verifying that a call should not have been made
|
174
|
+
|
175
|
+
Currently verifying that a call was not made does not take the arguments into consideration. It just ensures that no calls to a particular named method were made. Here is an example:
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
class FirstCollaborator
|
179
|
+
def send_message(message)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
class SecondCollaborator
|
183
|
+
def send_message(message)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
class SomeItem
|
188
|
+
def initialize
|
189
|
+
@first = FirstCollaborator.new
|
190
|
+
@second = SecondCollaborator.new
|
191
|
+
end
|
192
|
+
|
193
|
+
def first_behaviour
|
194
|
+
@first.send_message("Hello")
|
195
|
+
end
|
196
|
+
|
197
|
+
def second_behaviour
|
198
|
+
@second.send_message("World")
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe SomeItem do
|
203
|
+
context "when run" do
|
204
|
+
let(:first){fake}
|
205
|
+
let(:second){fake}
|
206
|
+
|
207
|
+
before(:each) do
|
208
|
+
FirstCollaborator.stub(:new).and_return(first)
|
209
|
+
SecondCollaborator.stub(:new).and_return(second)
|
210
|
+
@sut = SomeItem.new
|
211
|
+
end
|
212
|
+
|
213
|
+
before(:each) do
|
214
|
+
@sut.first_behaviour
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should trigger its collaborator with the correct message" do
|
218
|
+
first.should have_received(:send_message,"Hello")
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should not trigger its second collaborator" do
|
222
|
+
#again, here would be another option to use a convienience test utility method
|
223
|
+
second.never_received?(:send_message).should be_true
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
```
|
228
|
+
|
229
|
+
As you can see, in this test we want to verify that one collaborator was triggered and the other not.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/fakes.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib",__FILE__)
|
3
|
+
require "fakes/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "fakes"
|
7
|
+
s.version = Fakes::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Develop With Passion®"]
|
10
|
+
s.email = ["open_source@developwithpassion.com"]
|
11
|
+
s.homepage = "http://www.developwithpassion.com"
|
12
|
+
s.summary = %q{Simple faking library}
|
13
|
+
s.description = %q{Faking library that allows inspection of received calls after they have been made. Also supports tracking calls with multiple argument sets.}
|
14
|
+
s.rubyforge_project = "fakes"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_development_dependency "rspec"
|
23
|
+
s.add_development_dependency "rake"
|
24
|
+
s.add_development_dependency "guard"
|
25
|
+
s.add_development_dependency "guard-rspec"
|
26
|
+
s.add_runtime_dependency "developwithpassion_arrays"
|
27
|
+
end
|
data/lib/fakes.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Fakes
|
2
|
+
module ArgBehaviour
|
3
|
+
attr_accessor :return_value,:times_called
|
4
|
+
|
5
|
+
def and_return(item)
|
6
|
+
@return_value = item
|
7
|
+
end
|
8
|
+
|
9
|
+
def capture_args(args)
|
10
|
+
@times_called += 1
|
11
|
+
@called_args = args
|
12
|
+
end
|
13
|
+
|
14
|
+
def matches?(args)
|
15
|
+
return @args == args
|
16
|
+
end
|
17
|
+
|
18
|
+
def was_called_with?(args)
|
19
|
+
return @called_args == args
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/fakes/fake.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Fakes
|
2
|
+
class Fake
|
3
|
+
def initialize(invocation_set = {})
|
4
|
+
@method_invocations = invocation_set
|
5
|
+
end
|
6
|
+
|
7
|
+
def method_missing(name,*args,&block)
|
8
|
+
return @method_invocations.has_key?(name.to_sym) ? @method_invocations[name.to_sym].invoke(args) : handle_unexpected_method_invocation(name,args,block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def handle_unexpected_method_invocation(name,args,block)
|
12
|
+
method = stub(name.to_sym)
|
13
|
+
method.ignore_arg
|
14
|
+
return method.invoke(args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def stub(symbol)
|
18
|
+
return @method_invocations[symbol] || @method_invocations[symbol] = MethodStub.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def received(symbol)
|
22
|
+
return @method_invocations[symbol]
|
23
|
+
end
|
24
|
+
|
25
|
+
def never_received?(symbol)
|
26
|
+
return !@method_invocations.has_key?(symbol)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Fakes
|
2
|
+
class IgnoreSet
|
3
|
+
include ArgBehaviour
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
array :arg_sets do|a|
|
7
|
+
a.mutator :capture_args do|args|
|
8
|
+
@times_called += 1
|
9
|
+
@arg_sets << args
|
10
|
+
end
|
11
|
+
end
|
12
|
+
@times_called = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def matches?(args)
|
16
|
+
return true
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def was_called_with?(args)
|
21
|
+
return @arg_sets.select{|set| set == args}.count > 0
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Fakes
|
2
|
+
class MethodStub
|
3
|
+
def initialize(arg_sets = [])
|
4
|
+
array :arg_sets do|a|
|
5
|
+
a.mutator :add_new_set do|set|
|
6
|
+
@arg_sets << set
|
7
|
+
set
|
8
|
+
end
|
9
|
+
end
|
10
|
+
@arg_sets = arg_sets
|
11
|
+
end
|
12
|
+
|
13
|
+
def with(*args)
|
14
|
+
return add_new_set(ArgSet.new(args))
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def ignore_arg
|
19
|
+
return add_new_set(IgnoreSet.new)
|
20
|
+
end
|
21
|
+
|
22
|
+
def and_return(item)
|
23
|
+
ignore_arg.and_return(item)
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def invoke(args)
|
28
|
+
set = @arg_sets.find{|item| item.matches?(args)} || ignore_arg
|
29
|
+
set.capture_args(args)
|
30
|
+
return set.return_value
|
31
|
+
end
|
32
|
+
|
33
|
+
def called_with(*args)
|
34
|
+
return @arg_sets.find{|item| item.was_called_with?(args)}
|
35
|
+
end
|
36
|
+
|
37
|
+
def total_times_called
|
38
|
+
return @arg_sets.inject(0){|sum,item|sum += item.times_called}
|
39
|
+
end
|
40
|
+
|
41
|
+
def times?(value)
|
42
|
+
return total_times_called == value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Fakes
|
4
|
+
describe ArgBehaviour do
|
5
|
+
class AnArg
|
6
|
+
attr_accessor :called_args,:args
|
7
|
+
def initialize
|
8
|
+
@times_called = 0
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:sut){AnArg.new}
|
13
|
+
before (:each) do
|
14
|
+
sut.send(:extend,ArgBehaviour)
|
15
|
+
end
|
16
|
+
context "when a return value is specified" do
|
17
|
+
before (:each) do
|
18
|
+
sut.and_return(2)
|
19
|
+
end
|
20
|
+
it "should store the return value to be returned during invocation" do
|
21
|
+
sut.return_value.should == 2
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "when handling an invocation" do
|
26
|
+
before (:each) do
|
27
|
+
sut.capture_args(2)
|
28
|
+
end
|
29
|
+
it "should increment the number of times it was called" do
|
30
|
+
sut.times_called.should == 1
|
31
|
+
end
|
32
|
+
it "should store the arguments it was called with" do
|
33
|
+
sut.called_args.should == 2
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when matching a set of arguments" do
|
38
|
+
before (:each) do
|
39
|
+
sut.args = 2
|
40
|
+
end
|
41
|
+
it "should match if its own set of arguments are the same" do
|
42
|
+
sut.matches?(2).should be_true
|
43
|
+
sut.matches?(3).should be_false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "when matching a set of arguments that is passed in as a dictionary" do
|
48
|
+
before (:each) do
|
49
|
+
sut.args = {:id => 0,:name => "JP"}
|
50
|
+
end
|
51
|
+
it "should match if its hash is the same" do
|
52
|
+
sut.matches?(:id => 0,:name => "JP").should be_true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when determining whether it was called with a set of arguments" do
|
57
|
+
before (:each) do
|
58
|
+
sut.called_args = 2
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should match if the arguments are the same as the arguments it was invoked with" do
|
62
|
+
sut.was_called_with?(2).should be_true
|
63
|
+
sut.was_called_with?(3).should be_false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Fakes
|
4
|
+
describe Fake do
|
5
|
+
context "when stubbing a method" do
|
6
|
+
let(:invocations){Hash.new}
|
7
|
+
let(:sut){Fake.new(invocations)}
|
8
|
+
let(:symbol){:hello}
|
9
|
+
let(:new_method){Object.new}
|
10
|
+
|
11
|
+
context "and the method is not currently setup to be called" do
|
12
|
+
before (:each) do
|
13
|
+
MethodStub.stub(:new).and_return(new_method)
|
14
|
+
end
|
15
|
+
before (:each) do
|
16
|
+
@result = sut.stub(symbol)
|
17
|
+
end
|
18
|
+
it "should add a new method stub to the list of all invocations" do
|
19
|
+
invocations[symbol].should == new_method
|
20
|
+
end
|
21
|
+
it "should return the method invocation to continue specifying call behaviour" do
|
22
|
+
@result.should == new_method
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "and the method is already in the list of invocations" do
|
27
|
+
before (:each) do
|
28
|
+
invocations[symbol] = new_method
|
29
|
+
end
|
30
|
+
before (:each) do
|
31
|
+
@result = sut.stub(symbol)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should not readd the method to the list of invocations" do
|
35
|
+
invocations.count.should == 1
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should return the method invocation to continue specifying call behaviour" do
|
39
|
+
@result.should == new_method
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
context "when accessing the behaviour for a received call" do
|
44
|
+
let(:invocations){Hash.new}
|
45
|
+
let(:sut){Fake.new(invocations)}
|
46
|
+
let(:symbol){:hello}
|
47
|
+
let(:method_invocation){Object.new}
|
48
|
+
|
49
|
+
before (:each) do
|
50
|
+
invocations[symbol] = method_invocation
|
51
|
+
end
|
52
|
+
before (:each) do
|
53
|
+
@result = sut.received(symbol)
|
54
|
+
end
|
55
|
+
it "should return the method invocation for the called method" do
|
56
|
+
@result.should == method_invocation
|
57
|
+
end
|
58
|
+
end
|
59
|
+
context "when verifying whether a call was never received" do
|
60
|
+
let(:invocations){Hash.new}
|
61
|
+
let(:sut){Fake.new(invocations)}
|
62
|
+
let(:existing){:hello}
|
63
|
+
let(:method_invocation){Object.new}
|
64
|
+
|
65
|
+
before (:each) do
|
66
|
+
invocations[existing] = method_invocation
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
it "should base its decision on the list of received invocations" do
|
71
|
+
[:other,existing].each do|item|
|
72
|
+
sut.never_received?(item).should_not be_equal(invocations.has_key?(item))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
context "when method missing is triggered" do
|
77
|
+
class FakeInvocation
|
78
|
+
attr_accessor :invoke_was_called,:args,:return_value,:ignores_args
|
79
|
+
|
80
|
+
def initialize(return_value)
|
81
|
+
@return_value = return_value
|
82
|
+
end
|
83
|
+
|
84
|
+
def invoke(args)
|
85
|
+
@args = args
|
86
|
+
return @return_value
|
87
|
+
end
|
88
|
+
|
89
|
+
def ignore_arg
|
90
|
+
@ignores_args = true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
let(:invocations){Hash.new}
|
94
|
+
let(:sut){Fake.new(invocations)}
|
95
|
+
let(:symbol){:hello}
|
96
|
+
let(:invocation){FakeInvocation.new(Object.new)}
|
97
|
+
let(:args){"world"}
|
98
|
+
context "and the method is for an invocation that was prepared" do
|
99
|
+
before (:each) do
|
100
|
+
invocations[symbol] = invocation
|
101
|
+
end
|
102
|
+
before (:each) do
|
103
|
+
@result = sut.hello(args)
|
104
|
+
end
|
105
|
+
it "should trigger the invocation with the arguments" do
|
106
|
+
invocation.args.should == [args]
|
107
|
+
end
|
108
|
+
it "should return the result of triggering the invocation" do
|
109
|
+
@result.should == invocation.return_value
|
110
|
+
end
|
111
|
+
end
|
112
|
+
context "and the method is for an invocation that was not prepared" do
|
113
|
+
before (:each) do
|
114
|
+
MethodStub.stub(:new).and_return(invocation)
|
115
|
+
end
|
116
|
+
before (:each) do
|
117
|
+
@result = sut.hello(args)
|
118
|
+
end
|
119
|
+
it "should add a new invocation which ignores arguments to the list of all invocations" do
|
120
|
+
invocations.has_key?(:hello).should be_true
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should configure the new invocation to ignore all arguments" do
|
124
|
+
invocation.ignores_args.should be_true
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should invoke the invocation with the arguments" do
|
128
|
+
invocation.args.should == [args]
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should return the result of triggering the new invocation" do
|
132
|
+
@result.should == invocation.return_value
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "scenarios" do
|
138
|
+
context "setting up return values" do
|
139
|
+
it "should be able to intercept on methods that take a singular value" do
|
140
|
+
fake = Fake.new
|
141
|
+
fake.stub(:hello).with("World").and_return("Hello World")
|
142
|
+
fake.hello("World").should == "Hello World"
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should be able to intercept on methods that take a hash" do
|
146
|
+
fake = Fake.new
|
147
|
+
fake.stub(:hello).with(:id => "JP",:age => 33).and_return("Hello World")
|
148
|
+
fake.hello(:id => "JP",:age => 33).should == "Hello World"
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should be able to intercept on methods that take a value and a hash" do
|
152
|
+
fake = Fake.new
|
153
|
+
fake.stub(:hello).with(1,:id => "JP",:age => 33).and_return("Hello World")
|
154
|
+
|
155
|
+
fake.hello(1,:id => "JP",:age => 33).should == "Hello World"
|
156
|
+
fake.hello(2,:id => "JP",:age => 33).should be_nil
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should be able to intercept on methods that take an array" do
|
160
|
+
fake = Fake.new
|
161
|
+
fake.stub(:hello).with([1,2,3,4]).and_return("Hello World")
|
162
|
+
|
163
|
+
fake.hello([1,2,3,4]).should == "Hello World"
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should be able to intercept on methods that take an value, and an array" do
|
167
|
+
fake = Fake.new
|
168
|
+
fake.stub(:hello).with(1,[1,2,3,4]).and_return("Hello World")
|
169
|
+
|
170
|
+
fake.hello(1,[1,2,3,4]).should == "Hello World"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
context "verifying calls were made" do
|
174
|
+
it "should be able to intercept on methods that take a singular value" do
|
175
|
+
fake = Fake.new
|
176
|
+
fake.hello("World")
|
177
|
+
fake.received(:hello).called_with("World").should be_true
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should be able to intercept on methods that have no arguments" do
|
181
|
+
fake = Fake.new
|
182
|
+
fake.hello
|
183
|
+
fake.received(:hello).should_not be_nil
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
it "should be able to intercept on methods that take a hash" do
|
188
|
+
fake = Fake.new
|
189
|
+
fake.hello(:id => "JP",:age => 33)
|
190
|
+
fake.received(:hello).called_with(:id => "JP",:age => 33).should_not be_nil
|
191
|
+
fake.received(:hello).called_with(:id => "JS",:age => 33).should be_nil
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should be able to intercept on methods that take a value and a hash" do
|
195
|
+
fake = Fake.new
|
196
|
+
|
197
|
+
fake.hello(1,:id => "JP",:age => 33)
|
198
|
+
fake.received(:hello).called_with(1,:id => "JP",:age => 33).should_not be_nil
|
199
|
+
fake.received(:hello).called_with(1,:id => "JS",:age => 33).should be_nil
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should be able to intercept on methods that take an array" do
|
203
|
+
fake = Fake.new
|
204
|
+
|
205
|
+
fake.hello([1,2,3,4])
|
206
|
+
fake.received(:hello).called_with([1,2,3,4]).should_not be_nil
|
207
|
+
fake.received(:hello).called_with([1,2,3,5]).should be_nil
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should be able to intercept on methods that take an value, and an array" do
|
211
|
+
fake = Fake.new
|
212
|
+
fake.hello(1,[1,2,3,4])
|
213
|
+
|
214
|
+
fake.received(:hello).called_with(1,[1,2,3,4]).should_not be_nil
|
215
|
+
fake.received(:hello).called_with(1,[1,2,3,5]).should be_nil
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Fakes
|
4
|
+
describe IgnoreSet do
|
5
|
+
let(:sut){IgnoreSet.new}
|
6
|
+
|
7
|
+
context "when created" do
|
8
|
+
it "should initialize required members" do
|
9
|
+
sut.times_called.should == 0
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "when matching an argument set" do
|
14
|
+
it "should match any argument set" do
|
15
|
+
sut.matches?([1,2,3,4]).should be_true
|
16
|
+
sut.matches?([3,"hello",4,5]).should be_true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when capturing a set of arguments" do
|
21
|
+
before (:each) do
|
22
|
+
sut.capture_args(1)
|
23
|
+
sut.capture_args(2)
|
24
|
+
end
|
25
|
+
it "should store a list for each set of arguments" do
|
26
|
+
sut.arg_sets.count.should == 2
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when determining if it was called with a set of arguments" do
|
31
|
+
before (:each) do
|
32
|
+
sut.capture_args(1)
|
33
|
+
sut.capture_args(2)
|
34
|
+
end
|
35
|
+
it "should match if any of its argument sets match" do
|
36
|
+
sut.was_called_with?(2).should be_true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Fakes
|
4
|
+
describe MethodStub do
|
5
|
+
let(:args){[1,2,3]}
|
6
|
+
let(:argument_set){Object.new}
|
7
|
+
|
8
|
+
context "when specifying a set of arguments it should be called with" do
|
9
|
+
let(:arg_sets){[]}
|
10
|
+
let(:sut){MethodStub.new(arg_sets)}
|
11
|
+
|
12
|
+
before (:each) do
|
13
|
+
ArgSet.stub(:new).with([args]).and_return(argument_set)
|
14
|
+
end
|
15
|
+
before (:each) do
|
16
|
+
@result = sut.with(args)
|
17
|
+
end
|
18
|
+
it "should add a new argument set to its list of arguments" do
|
19
|
+
arg_sets[0].should == argument_set
|
20
|
+
end
|
21
|
+
it "should return the argument set to continue specifying behaviour" do
|
22
|
+
@result.should == argument_set
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when ignoring arguments" do
|
27
|
+
let(:ignored_set){Object.new}
|
28
|
+
let(:arg_sets){[]}
|
29
|
+
let(:sut){MethodStub.new(arg_sets)}
|
30
|
+
|
31
|
+
before (:each) do
|
32
|
+
IgnoreSet.stub(:new).and_return(ignored_set)
|
33
|
+
end
|
34
|
+
before (:each) do
|
35
|
+
@result = sut.ignore_arg
|
36
|
+
end
|
37
|
+
it "should add the ignored set to the list of argument sets" do
|
38
|
+
arg_sets[0].should == ignored_set
|
39
|
+
end
|
40
|
+
it "should return the ignored set to specify other behaviour" do
|
41
|
+
@result.should == ignored_set
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when invoked with a set of arguments" do
|
46
|
+
let(:arg_sets){[]}
|
47
|
+
let(:sut){MethodStub.new(arg_sets)}
|
48
|
+
class DummyArgSet
|
49
|
+
attr_accessor :args
|
50
|
+
|
51
|
+
def capture_args(*args)
|
52
|
+
@args = *args
|
53
|
+
end
|
54
|
+
end
|
55
|
+
context "and it has the specified argument set" do
|
56
|
+
let(:arguments){[1]}
|
57
|
+
let(:arg_set){DummyArgSet.new}
|
58
|
+
before (:each) do
|
59
|
+
arg_sets.push(arg_set)
|
60
|
+
arg_set.stub(:matches?).and_return(true)
|
61
|
+
arg_set.stub(:return_value).and_return(2)
|
62
|
+
end
|
63
|
+
before (:each) do
|
64
|
+
@result = sut.invoke(arguments)
|
65
|
+
end
|
66
|
+
it "should tell the argument set to capture the arguments it was called with" do
|
67
|
+
arg_set.args.should == [arguments]
|
68
|
+
end
|
69
|
+
it "should return using from the arg set" do
|
70
|
+
@result.should == 2
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
context "and it does not have the specified argument set" do
|
75
|
+
let(:arguments){[1]}
|
76
|
+
let(:arg_set){DummyArgSet.new}
|
77
|
+
before (:each) do
|
78
|
+
sut.stub(:ignore_arg).and_return(arg_set)
|
79
|
+
arg_set.stub(:return_value).and_return(2)
|
80
|
+
end
|
81
|
+
before (:each) do
|
82
|
+
@result = sut.invoke(arguments)
|
83
|
+
end
|
84
|
+
it "should tell the argument set to capture the arguments it was called with" do
|
85
|
+
arg_set.args.should == [arguments]
|
86
|
+
end
|
87
|
+
it "should return using from the missing arg set" do
|
88
|
+
@result.should == 2
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
context "when determining whether it was called with a set of arguments" do
|
95
|
+
let(:arg_sets){[]}
|
96
|
+
let(:sut){MethodStub.new(arg_sets)}
|
97
|
+
class DummyArgSet
|
98
|
+
attr_accessor :args
|
99
|
+
|
100
|
+
def capture_args(*args)
|
101
|
+
@args = *args
|
102
|
+
end
|
103
|
+
end
|
104
|
+
let(:arguments){1}
|
105
|
+
|
106
|
+
context "and one of its argument sets was called with the set of arguments" do
|
107
|
+
let(:arg_set){DummyArgSet.new}
|
108
|
+
before (:each) do
|
109
|
+
arg_sets.push(arg_set)
|
110
|
+
arg_set.stub(:was_called_with?).with([arguments]).and_return(true)
|
111
|
+
end
|
112
|
+
before (:each) do
|
113
|
+
@result = sut.called_with(arguments)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should return the argument set that was called with the arguments" do
|
117
|
+
@result.should == arg_set
|
118
|
+
end
|
119
|
+
end
|
120
|
+
context "and none of its argument sets were called with the arguments" do
|
121
|
+
before (:each) do
|
122
|
+
@result = sut.called_with(arguments)
|
123
|
+
end
|
124
|
+
it "should return nil" do
|
125
|
+
@result.should be_nil
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
context "when retrieving the total number of times called" do
|
132
|
+
let(:arg_sets){[]}
|
133
|
+
let(:sut){MethodStub.new(arg_sets)}
|
134
|
+
let(:arg_set){DummyArgSet.new}
|
135
|
+
let(:arg_set_2){DummyArgSet.new}
|
136
|
+
|
137
|
+
before (:each) do
|
138
|
+
arg_sets.push(arg_set)
|
139
|
+
arg_sets.push(arg_set_2)
|
140
|
+
arg_set.stub(:times_called).and_return(2)
|
141
|
+
arg_set_2.stub(:times_called).and_return(3)
|
142
|
+
end
|
143
|
+
|
144
|
+
it "it should return the sum of the invocations of its argument sets" do
|
145
|
+
sut.total_times_called.should == 5
|
146
|
+
end
|
147
|
+
end
|
148
|
+
context "when verifying whether it was called a certain number of times" do
|
149
|
+
let(:arg_sets){[]}
|
150
|
+
let(:sut){MethodStub.new(arg_sets)}
|
151
|
+
let(:arg_set){DummyArgSet.new}
|
152
|
+
let(:arg_set_2){DummyArgSet.new}
|
153
|
+
|
154
|
+
before (:each) do
|
155
|
+
arg_sets.push(arg_set)
|
156
|
+
arg_sets.push(arg_set_2)
|
157
|
+
arg_set.stub(:times_called).and_return(2)
|
158
|
+
arg_set_2.stub(:times_called).and_return(3)
|
159
|
+
end
|
160
|
+
|
161
|
+
it "it should return whether the sum of its argset invocations is the same as the number of request made" do
|
162
|
+
sut.times?(5).should be_true
|
163
|
+
sut.times?(3).should be_false
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
metadata
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fakes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Develop With Passion®
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: guard
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: guard-rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: developwithpassion_arrays
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: Faking library that allows inspection of received calls after they have
|
95
|
+
been made. Also supports tracking calls with multiple argument sets.
|
96
|
+
email:
|
97
|
+
- open_source@developwithpassion.com
|
98
|
+
executables: []
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- .gitignore
|
103
|
+
- .rvmrc
|
104
|
+
- Gemfile
|
105
|
+
- Guardfile
|
106
|
+
- README.md
|
107
|
+
- Rakefile
|
108
|
+
- fakes.gemspec
|
109
|
+
- lib/fakes.rb
|
110
|
+
- lib/fakes/arg_behaviour.rb
|
111
|
+
- lib/fakes/arg_set.rb
|
112
|
+
- lib/fakes/fake.rb
|
113
|
+
- lib/fakes/ignore_set.rb
|
114
|
+
- lib/fakes/method_stub.rb
|
115
|
+
- lib/fakes/version.rb
|
116
|
+
- spec/spec_helper.rb
|
117
|
+
- spec/specs/arg_behaviour_spec.rb
|
118
|
+
- spec/specs/arg_set_spec.rb
|
119
|
+
- spec/specs/fake_spec.rb
|
120
|
+
- spec/specs/ignore_set_spec.rb
|
121
|
+
- spec/specs/kernel_spec.rb
|
122
|
+
- spec/specs/method_stub_spec.rb
|
123
|
+
homepage: http://www.developwithpassion.com
|
124
|
+
licenses: []
|
125
|
+
post_install_message:
|
126
|
+
rdoc_options: []
|
127
|
+
require_paths:
|
128
|
+
- lib
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
131
|
+
requirements:
|
132
|
+
- - ! '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
none: false
|
137
|
+
requirements:
|
138
|
+
- - ! '>='
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubyforge_project: fakes
|
143
|
+
rubygems_version: 1.8.21
|
144
|
+
signing_key:
|
145
|
+
specification_version: 3
|
146
|
+
summary: Simple faking library
|
147
|
+
test_files:
|
148
|
+
- spec/spec_helper.rb
|
149
|
+
- spec/specs/arg_behaviour_spec.rb
|
150
|
+
- spec/specs/arg_set_spec.rb
|
151
|
+
- spec/specs/fake_spec.rb
|
152
|
+
- spec/specs/ignore_set_spec.rb
|
153
|
+
- spec/specs/kernel_spec.rb
|
154
|
+
- spec/specs/method_stub_spec.rb
|