developwithpassion_fakes 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/developwithpassion_fakes.gemspec +27 -0
- data/lib/developwithpassion_fakes/arg_behaviour.rb +24 -0
- data/lib/developwithpassion_fakes/arg_set.rb +12 -0
- data/lib/developwithpassion_fakes/fake.rb +31 -0
- data/lib/developwithpassion_fakes/ignore_set.rb +26 -0
- data/lib/developwithpassion_fakes/method_stub.rb +42 -0
- data/lib/developwithpassion_fakes/version.rb +5 -0
- data/lib/developwithpassion_fakes.rb +11 -0
- metadata +17 -15
- data/.gitignore +0 -5
- data/.rvmrc +0 -1
- data/Gemfile +0 -3
- data/Guardfile +0 -5
- data/README.md +0 -229
- data/Rakefile +0 -1
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib",__FILE__)
|
3
|
+
require "developwithpassion_fakes/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "developwithpassion_fakes"
|
7
|
+
s.version = DevelopWithPassion::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 = "developwithpassion_fakes"
|
15
|
+
|
16
|
+
s.files = `git ls-files | grep -P "^(dev|lib)"`.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-core"
|
23
|
+
s.add_development_dependency "rspec-expectations"
|
24
|
+
s.add_development_dependency "rake"
|
25
|
+
s.add_development_dependency "guard"
|
26
|
+
# s.add_runtime_dependency "rest-client"
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module DevelopWithPassion
|
2
|
+
module Fakes
|
3
|
+
module ArgBehaviour
|
4
|
+
attr_accessor :return_value,:times_called
|
5
|
+
|
6
|
+
def and_return(item)
|
7
|
+
@return_value = item
|
8
|
+
end
|
9
|
+
|
10
|
+
def capture_args(args)
|
11
|
+
@times_called += 1
|
12
|
+
@called_args = args
|
13
|
+
end
|
14
|
+
|
15
|
+
def matches?(args)
|
16
|
+
return @args == args
|
17
|
+
end
|
18
|
+
|
19
|
+
def was_called_with?(args)
|
20
|
+
return @called_args == args
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module DevelopWithPassion
|
2
|
+
module Fakes
|
3
|
+
class Fake
|
4
|
+
def initialize(invocation_set = {})
|
5
|
+
@method_invocations = invocation_set
|
6
|
+
end
|
7
|
+
|
8
|
+
def method_missing(name,*args,&block)
|
9
|
+
return @method_invocations.has_key?(name.to_sym) ? @method_invocations[name.to_sym].invoke(args) : handle_unexpected_method_invocation(name,args,block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def handle_unexpected_method_invocation(name,args,block)
|
13
|
+
method = stub(name.to_sym)
|
14
|
+
method.ignore_arg
|
15
|
+
return method.invoke(args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def stub(symbol)
|
19
|
+
return @method_invocations[symbol] || @method_invocations[symbol] = MethodStub.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def received(symbol)
|
23
|
+
return @method_invocations[symbol]
|
24
|
+
end
|
25
|
+
|
26
|
+
def never_received?(symbol)
|
27
|
+
return !@method_invocations.has_key?(symbol)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module DevelopWithPassion
|
2
|
+
module Fakes
|
3
|
+
class IgnoreSet
|
4
|
+
include ArgBehaviour
|
5
|
+
attr_reader :arg_sets
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@times_called = 0
|
9
|
+
@arg_sets = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def matches?(args)
|
13
|
+
return true
|
14
|
+
end
|
15
|
+
|
16
|
+
def capture_args(args)
|
17
|
+
@times_called += 1
|
18
|
+
@arg_sets << args
|
19
|
+
end
|
20
|
+
|
21
|
+
def was_called_with?(args)
|
22
|
+
return @arg_sets.select{|set| set == args}.count > 0
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module DevelopWithPassion
|
2
|
+
module Fakes
|
3
|
+
class MethodStub
|
4
|
+
def initialize(arg_sets = [])
|
5
|
+
@arg_sets = arg_sets
|
6
|
+
end
|
7
|
+
|
8
|
+
def with(*args)
|
9
|
+
return add_new_set(ArgSet.new(args))
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_new_set(set)
|
13
|
+
@arg_sets << set
|
14
|
+
return set
|
15
|
+
end
|
16
|
+
|
17
|
+
def ignore_arg
|
18
|
+
return add_new_set(IgnoreSet.new)
|
19
|
+
end
|
20
|
+
|
21
|
+
def and_return(item)
|
22
|
+
ignore_arg.and_return(item)
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def invoke(args)
|
27
|
+
set = @arg_sets.find{|item| item.matches?(args)} || ignore_arg
|
28
|
+
set.capture_args(args)
|
29
|
+
return set.return_value
|
30
|
+
end
|
31
|
+
|
32
|
+
def called_with(*args)
|
33
|
+
return @arg_sets.find{|item| item.was_called_with?(args)}
|
34
|
+
end
|
35
|
+
|
36
|
+
def times?(value)
|
37
|
+
total = @arg_sets.inject(0){|sum,item|sum += item.times_called}
|
38
|
+
return total == value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'developwithpassion_fakes/arg_behaviour'
|
2
|
+
require 'developwithpassion_fakes/arg_set'
|
3
|
+
require 'developwithpassion_fakes/fake'
|
4
|
+
require 'developwithpassion_fakes/ignore_set'
|
5
|
+
require 'developwithpassion_fakes/method_stub'
|
6
|
+
|
7
|
+
module Kernel
|
8
|
+
def fake
|
9
|
+
return DevelopWithPassion::Fakes::Fake.new
|
10
|
+
end
|
11
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: developwithpassion_fakes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-03-25 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec-core
|
16
|
-
requirement: &
|
16
|
+
requirement: &70230798759920 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70230798759920
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec-expectations
|
27
|
-
requirement: &
|
27
|
+
requirement: &70230798759400 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70230798759400
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rake
|
38
|
-
requirement: &
|
38
|
+
requirement: &70230798758940 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70230798758940
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: guard
|
49
|
-
requirement: &
|
49
|
+
requirement: &70230798758500 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70230798758500
|
58
58
|
description: Faking library that allows inspection of received calls after they have
|
59
59
|
been made. Also supports tracking calls with multiple argument sets.
|
60
60
|
email:
|
@@ -63,12 +63,14 @@ executables: []
|
|
63
63
|
extensions: []
|
64
64
|
extra_rdoc_files: []
|
65
65
|
files:
|
66
|
-
- .
|
67
|
-
- .
|
68
|
-
-
|
69
|
-
-
|
70
|
-
-
|
71
|
-
-
|
66
|
+
- developwithpassion_fakes.gemspec
|
67
|
+
- lib/developwithpassion_fakes.rb
|
68
|
+
- lib/developwithpassion_fakes/arg_behaviour.rb
|
69
|
+
- lib/developwithpassion_fakes/arg_set.rb
|
70
|
+
- lib/developwithpassion_fakes/fake.rb
|
71
|
+
- lib/developwithpassion_fakes/ignore_set.rb
|
72
|
+
- lib/developwithpassion_fakes/method_stub.rb
|
73
|
+
- lib/developwithpassion_fakes/version.rb
|
72
74
|
- spec/spec_helper.rb
|
73
75
|
- spec/specs/arg_behaviour_spec.rb
|
74
76
|
- spec/specs/arg_set_spec.rb
|
data/.gitignore
DELETED
data/.rvmrc
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
rvm 1.9.3@developwithpassion_fakes --create
|
data/Gemfile
DELETED
data/Guardfile
DELETED
data/README.md
DELETED
@@ -1,229 +0,0 @@
|
|
1
|
-
#developwithpassion_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){DevelopWithPassion::Fakes::Fake.new}
|
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 'developwithpassion_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
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require "bundler/gem_tasks"
|