adequack 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +229 -0
- data/Rakefile +5 -0
- data/adequack.gemspec +25 -0
- data/lib/adequack/core.rb +43 -0
- data/lib/adequack/integration/rspec_setup.rb +21 -0
- data/lib/adequack/proxy.rb +86 -0
- data/lib/adequack/version.rb +3 -0
- data/lib/adequack.rb +16 -0
- data/spec/adequack_spec.rb +129 -0
- data/spec/integration_spec.rb +64 -0
- data/spec/spec_helper.rb +1 -0
- metadata +104 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6cbd122c01215eb0d14f941fc68ecb1f147bfe3b
|
4
|
+
data.tar.gz: 1dbcf7bc56ae09478d86f0ae47b6fe4f4db6040d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 93f3f69ffbfaf2c76ca608bcc3bf4d1c51e652f601e203d08f59b601dbe2d86b11669b55237cda7671dd800783d262ce28bde0df55fc66834d6750ce4e7ec49a
|
7
|
+
data.tar.gz: 13c964cd0d085001f92330d13468b149c49c2a820f756ca4ff2e571aaf369cdddad0057b41fe7266ae811129aac7e81b43f6386173b4e2540fc511f46fd6e75b
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Ilya Zayats
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
# Adequack
|
2
|
+
|
3
|
+
Everyone likes isolation testing now. And when you do it then you stubbing and mocking a lot.
|
4
|
+
But the main concern when you use this approach is that you stubs will be out of sync with the
|
5
|
+
real objects.
|
6
|
+
Adequack addresses this issue.
|
7
|
+
|
8
|
+
## Problem 1. Missing methods
|
9
|
+
|
10
|
+
Let's dive into this toy code:
|
11
|
+
```ruby
|
12
|
+
class Dog
|
13
|
+
def eat_food
|
14
|
+
puts "delicious!"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Owner
|
19
|
+
def initialize(dog)
|
20
|
+
@dog = dog
|
21
|
+
end
|
22
|
+
|
23
|
+
def feed_animal
|
24
|
+
@dog.eat_food
|
25
|
+
end
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
and we are going to spec things out:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
describe Owner do
|
33
|
+
let(:dog) { double }
|
34
|
+
subject { described_class.new dog }
|
35
|
+
|
36
|
+
it "feeds animal" do
|
37
|
+
dog.should_receive(:eat_food)
|
38
|
+
subject.feed_animal
|
39
|
+
end
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
And everything will pass.
|
44
|
+
|
45
|
+
But let's imagine that a big dog food brand will come to us and pay a lot for branding:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
class Dog
|
49
|
+
def eat_chappi
|
50
|
+
puts "delicious chappi dog food! I will recommend it to all my buddies!"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
So we've changed our code and we should run the tests:
|
56
|
+
|
57
|
+
```
|
58
|
+
.
|
59
|
+
|
60
|
+
Finished in 0.00051 seconds
|
61
|
+
1 example, 0 failures
|
62
|
+
```
|
63
|
+
|
64
|
+
You are very confident about your test suite and you decide to deploy the changes to production.
|
65
|
+
After that big dog food brand will take that payment away because of:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
undefined method `eat_food' for #<Dog:0x99250dc>
|
69
|
+
```
|
70
|
+
|
71
|
+
### Solving this with adequack
|
72
|
+
|
73
|
+
Let's replay the story again but with a happy end:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
require 'adequack'
|
77
|
+
|
78
|
+
module DogInterface
|
79
|
+
def eat_food; end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe Dog do
|
83
|
+
subject { described_class }
|
84
|
+
it { should be_adequack_to DogInterface }
|
85
|
+
end
|
86
|
+
|
87
|
+
describe Owner do
|
88
|
+
let(:dog) { adequack_double double, DogInterface }
|
89
|
+
subject { described_class.new dog }
|
90
|
+
|
91
|
+
it "feeds animal" do
|
92
|
+
dog.should_receive(:eat_food)
|
93
|
+
subject.feed_animal
|
94
|
+
end
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
and we will have 2 passing dots:
|
99
|
+
|
100
|
+
```
|
101
|
+
.
|
102
|
+
|
103
|
+
Finished in 0.00128 seconds
|
104
|
+
2 examples, 0 failures
|
105
|
+
```
|
106
|
+
|
107
|
+
We should validate not only our mocks, but also that our core object really responds to the interface.
|
108
|
+
Use `be_adequack_to` matcher with a core class as an argument.
|
109
|
+
|
110
|
+
And to create doubles and stubs use `adequack_double` helper. This will return a proxy object that
|
111
|
+
will translate all calls to the object that you'll pass first (plain `double` at the example).
|
112
|
+
|
113
|
+
Let's replay our changes again:
|
114
|
+
```ruby
|
115
|
+
class Dog
|
116
|
+
def eat_chappi
|
117
|
+
puts "delicious chappi dog food! I will recommend it to all my buddies!"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
and run our specs:
|
123
|
+
```
|
124
|
+
F.
|
125
|
+
|
126
|
+
Failures:
|
127
|
+
|
128
|
+
1) Dog
|
129
|
+
Failure/Error: it { should be_adequack_to DogInterface }
|
130
|
+
Adequack::InterfaceImplementationError:
|
131
|
+
object does not respond to 'eat_food' method
|
132
|
+
|
133
|
+
```
|
134
|
+
|
135
|
+
Here we gon an error at the dog spec, because our core object falls out of sync with our interface.
|
136
|
+
But big sponsor is paying, so we will change the interface too:
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
module DogInterface
|
140
|
+
def eat_chappi; end
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
and rerun our tests:
|
145
|
+
```
|
146
|
+
.F
|
147
|
+
|
148
|
+
Failures:
|
149
|
+
|
150
|
+
1) Owner feeds animal
|
151
|
+
Failure/Error: dog.should_receive(:eat_food)
|
152
|
+
Adequack::InterfaceImplementationError:
|
153
|
+
trying to stub nonexistent method
|
154
|
+
|
155
|
+
```
|
156
|
+
|
157
|
+
Another failure, we should change our stubs too!
|
158
|
+
|
159
|
+
And at this time we will ger our payment fully.
|
160
|
+
|
161
|
+
## Problem 2. Method signatures
|
162
|
+
|
163
|
+
But what if method is there, but signature is changed?
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
class Dog
|
167
|
+
def eat_food(brand)
|
168
|
+
puts "delicious #{brand} dog food! I will recommend it to all my buddies!"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
```
|
172
|
+
|
173
|
+
and our specs will tell you about that:
|
174
|
+
|
175
|
+
```
|
176
|
+
.F
|
177
|
+
|
178
|
+
Failures:
|
179
|
+
|
180
|
+
1) Owner feeds animal
|
181
|
+
Failure/Error: @dog.eat_food
|
182
|
+
Adequack::InterfaceImplementationError:
|
183
|
+
definition of method 'eat_food' differs in parameters accepted.
|
184
|
+
```
|
185
|
+
|
186
|
+
## Installation
|
187
|
+
|
188
|
+
Just install the gem
|
189
|
+
```
|
190
|
+
gem install adequack
|
191
|
+
```
|
192
|
+
|
193
|
+
and require it when you need it: `require 'adequack'`
|
194
|
+
|
195
|
+
After that your rspec tests will have `be_adequack_to` matcher and `adequack_double` helper.
|
196
|
+
|
197
|
+
## Usage
|
198
|
+
|
199
|
+
TODO: Write full API definition here
|
200
|
+
|
201
|
+
## Contributing
|
202
|
+
|
203
|
+
This library is considered "experimental" quality.
|
204
|
+
Your feedback would be very welcome! Pull requests are great, but issues are good too.
|
205
|
+
|
206
|
+
## Licence
|
207
|
+
|
208
|
+
Copyright (c) 2013 Ilya Zayats
|
209
|
+
|
210
|
+
MIT License
|
211
|
+
|
212
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
213
|
+
a copy of this software and associated documentation files (the
|
214
|
+
"Software"), to deal in the Software without restriction, including
|
215
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
216
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
217
|
+
permit persons to whom the Software is furnished to do so, subject to
|
218
|
+
the following conditions:
|
219
|
+
|
220
|
+
The above copyright notice and this permission notice shall be
|
221
|
+
included in all copies or substantial portions of the Software.
|
222
|
+
|
223
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
224
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
225
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
226
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
227
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
228
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
229
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
data/adequack.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'adequack/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "adequack"
|
8
|
+
spec.version = Adequack::VERSION
|
9
|
+
spec.authors = ["Ilya Zayats"]
|
10
|
+
spec.email = ["somebody32@gmail.com"]
|
11
|
+
spec.description = %q{Be sure that your mocks are adequate}
|
12
|
+
spec.summary = %q{Be sure that your mocks are adequate}
|
13
|
+
spec.homepage = "https://github.com/Somebody32/adequack"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "rspec", "~> 2.13"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Adequack
|
2
|
+
class Core
|
3
|
+
|
4
|
+
def self.implements(object, interface)
|
5
|
+
new(object, interface).send(:validate_ducktype)
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def initialize(duck, interface)
|
11
|
+
self.duck = duck
|
12
|
+
self.interface = interface
|
13
|
+
end
|
14
|
+
|
15
|
+
def validate_ducktype
|
16
|
+
check_method_implementation(get_methods interface.public_methods )
|
17
|
+
check_method_implementation(
|
18
|
+
get_methods(interface.public_instance_methods), true
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def check_method_implementation(methods, instance = false)
|
23
|
+
methods.each do |method|
|
24
|
+
if instance
|
25
|
+
name = method
|
26
|
+
defined = duck.method_defined?(method)
|
27
|
+
else
|
28
|
+
name = "self.#{method}"
|
29
|
+
defined = duck.respond_to?(method)
|
30
|
+
end
|
31
|
+
|
32
|
+
raise InterfaceImplementationError,
|
33
|
+
"object does not respond to '#{name}' method" unless defined
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_accessor :duck, :interface
|
38
|
+
|
39
|
+
def get_methods(methods)
|
40
|
+
methods - Object.methods
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Adequack
|
2
|
+
module Integration
|
3
|
+
module RSpecHelpers
|
4
|
+
def adequack_double(object, interface)
|
5
|
+
Adequack.double object, interface
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
RSpec::Matchers.define :be_adequack_to do |*expected_duck_types|
|
12
|
+
expected_duck_types.each do |expected_duck_type|
|
13
|
+
match do |actual|
|
14
|
+
Adequack.check_implementation(actual, expected_duck_type)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec.configure do |config|
|
20
|
+
config.include Adequack::Integration::RSpecHelpers
|
21
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Adequack
|
2
|
+
class Proxy
|
3
|
+
|
4
|
+
def initialize(target, interface)
|
5
|
+
self.target = target
|
6
|
+
self.interface = interface
|
7
|
+
end
|
8
|
+
|
9
|
+
def stub(message_or_hash, opts = {}, &block)
|
10
|
+
methods =
|
11
|
+
Hash === message_or_hash ? message_or_hash.keys : [message_or_hash]
|
12
|
+
|
13
|
+
methods.each { |m| check_method_existence m }
|
14
|
+
|
15
|
+
target.stub(message_or_hash, opts, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method :stub!, :stub
|
19
|
+
|
20
|
+
def stub_chain(*chain, &blk)
|
21
|
+
method =
|
22
|
+
String === chain.first ? chain.first.split(".").first : chain.first
|
23
|
+
|
24
|
+
check_method_existence method
|
25
|
+
|
26
|
+
target.stub_chain(*chain, &blk)
|
27
|
+
end
|
28
|
+
|
29
|
+
def should_receive(message, opts = {}, &block)
|
30
|
+
check_method_existence message
|
31
|
+
|
32
|
+
target.should_receive(message, opts, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
attr_accessor :target, :interface
|
38
|
+
|
39
|
+
def method_missing(name, *args, &block)
|
40
|
+
check_interface_implementation name, args
|
41
|
+
target.send name, *args, &block
|
42
|
+
end
|
43
|
+
|
44
|
+
def check_interface_implementation(name, args)
|
45
|
+
check_interface_signature(name, args) if method_in_interface?(name)
|
46
|
+
end
|
47
|
+
|
48
|
+
def check_interface_signature(name, args)
|
49
|
+
target_method = duck_type_methods.select { |m| m.name == name }.first
|
50
|
+
req_m = target_method.parameters.select { |m| m.first == :req }
|
51
|
+
|
52
|
+
if args.size < req_m.size
|
53
|
+
raise InterfaceImplementationError,
|
54
|
+
"definition of method '#{name}' differs in parameters accepted."
|
55
|
+
end
|
56
|
+
|
57
|
+
unless target_method.parameters.any? { |m| m.first == :rest }
|
58
|
+
opt_m = target_method.parameters.select { |m| m.first == :opt }
|
59
|
+
|
60
|
+
if args.size > (req_m.size + opt_m.size)
|
61
|
+
raise InterfaceImplementationError,
|
62
|
+
"definition of method '#{name}' differs in parameters accepted."
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def check_method_existence(method)
|
68
|
+
unless method_in_interface? method
|
69
|
+
raise InterfaceImplementationError,
|
70
|
+
"trying to stub nonexistent method"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def method_in_interface?(method)
|
75
|
+
duck_type_methods.map(&:name).include? method.to_sym
|
76
|
+
end
|
77
|
+
|
78
|
+
def duck_type_methods
|
79
|
+
@duck_type_methods ||= (interface.instance_methods - Object.methods)
|
80
|
+
@duck_type_methods.map do |method_name|
|
81
|
+
interface.public_instance_method(method_name)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
data/lib/adequack.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "adequack/version"
|
2
|
+
require "adequack/core"
|
3
|
+
require "adequack/proxy"
|
4
|
+
require "adequack/integration/rspec_setup"
|
5
|
+
|
6
|
+
module Adequack
|
7
|
+
InterfaceImplementationError = Class.new(::StandardError)
|
8
|
+
|
9
|
+
def self.check_implementation(duck, interface)
|
10
|
+
Core.implements duck, interface
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.double(core, interface)
|
14
|
+
Proxy.new core, interface
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Adequack do
|
4
|
+
|
5
|
+
let!(:interface) do
|
6
|
+
Class.new do
|
7
|
+
def self.evolutionize; end
|
8
|
+
def bark(what); end
|
9
|
+
def eat(tasty = true); end
|
10
|
+
def drink(what, many = true); end
|
11
|
+
def sleep(how_long, *places); end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
before do
|
16
|
+
Object.send(:remove_const, :Animal) if Object.const_defined?(:Animal)
|
17
|
+
end
|
18
|
+
|
19
|
+
context "when checking interface implementation" do
|
20
|
+
|
21
|
+
it "passes when test class is ok" do
|
22
|
+
class Animal
|
23
|
+
def self.evolutionize; end
|
24
|
+
def bark(what); end
|
25
|
+
def eat(tasty = true); end
|
26
|
+
def drink(what, many = true); end
|
27
|
+
def sleep(how_long, *places); end
|
28
|
+
end
|
29
|
+
|
30
|
+
expect { described_class.check_implementation(Animal, interface) }.
|
31
|
+
not_to raise_error Adequack::InterfaceImplementationError
|
32
|
+
end
|
33
|
+
|
34
|
+
it "fails when no class method" do
|
35
|
+
class Animal
|
36
|
+
def bark(what); end
|
37
|
+
def eat(tasty = true); end
|
38
|
+
def drink(what, many = true); end
|
39
|
+
def sleep(how_long, *places); end
|
40
|
+
end
|
41
|
+
|
42
|
+
expect { described_class.check_implementation(Animal, interface) }.
|
43
|
+
to raise_error Adequack::InterfaceImplementationError,
|
44
|
+
"object does not respond to 'self.evolutionize' method"
|
45
|
+
end
|
46
|
+
|
47
|
+
it "will not take care about private and protected methods" do
|
48
|
+
class Animal
|
49
|
+
def bark(what); end
|
50
|
+
end
|
51
|
+
|
52
|
+
bad_interface = Class.new do
|
53
|
+
def bark(what); end
|
54
|
+
|
55
|
+
class << self
|
56
|
+
protected
|
57
|
+
def c_a; end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.c_b; end
|
61
|
+
private_class_method :c_b
|
62
|
+
|
63
|
+
protected
|
64
|
+
def a; end
|
65
|
+
|
66
|
+
private
|
67
|
+
def b; end
|
68
|
+
end
|
69
|
+
|
70
|
+
expect { described_class.check_implementation(Animal, bad_interface) }.
|
71
|
+
not_to raise_error Adequack::InterfaceImplementationError
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
context "when stubbing and mocking" do
|
77
|
+
|
78
|
+
let(:core) { double }
|
79
|
+
let(:subject) { Adequack.double core, interface }
|
80
|
+
|
81
|
+
it "let you stub methods that exists and return actual object" do
|
82
|
+
core.should_receive(:stub).with({ bark: "woof" }, {})
|
83
|
+
subject.stub(bark: "woof")
|
84
|
+
end
|
85
|
+
|
86
|
+
it "raises an error if trying to stub nonexistent method via hash" do
|
87
|
+
expect { subject.stub(muuuu: "hey hoo") }.
|
88
|
+
to raise_error Adequack::InterfaceImplementationError,
|
89
|
+
"trying to stub nonexistent method"
|
90
|
+
end
|
91
|
+
|
92
|
+
it "raises an error if trying to stub nonexistent method via message" do
|
93
|
+
expect { subject.stub(:muuuu) }.
|
94
|
+
to raise_error Adequack::InterfaceImplementationError,
|
95
|
+
"trying to stub nonexistent method"
|
96
|
+
end
|
97
|
+
|
98
|
+
it "works with chaining" do
|
99
|
+
core.should_receive(:stub_chain).with("bark.words")
|
100
|
+
subject.stub_chain("bark.words")
|
101
|
+
end
|
102
|
+
|
103
|
+
it "raises if chain in symbol form" do
|
104
|
+
expect { subject.stub_chain(:tongue, :skin) }.
|
105
|
+
to raise_error Adequack::InterfaceImplementationError,
|
106
|
+
"trying to stub nonexistent method"
|
107
|
+
end
|
108
|
+
|
109
|
+
it "raises if chain in string form" do
|
110
|
+
expect { subject.stub_chain("tongue.skin") }.
|
111
|
+
to raise_error Adequack::InterfaceImplementationError,
|
112
|
+
"trying to stub nonexistent method"
|
113
|
+
end
|
114
|
+
|
115
|
+
it "works with should receive too" do
|
116
|
+
expect { subject.should_receive(:muuuu) }.
|
117
|
+
to raise_error Adequack::InterfaceImplementationError,
|
118
|
+
"trying to stub nonexistent method"
|
119
|
+
end
|
120
|
+
|
121
|
+
it "tell you if you'r passing invalid arguments" do
|
122
|
+
expect {
|
123
|
+
core.should_not_receive(:bark)
|
124
|
+
subject.bark("woof", "not woof")
|
125
|
+
}.to raise_error Adequack::InterfaceImplementationError,
|
126
|
+
"definition of method 'bark' differs in parameters accepted."
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module AnimalInterface
|
4
|
+
def self.evolutionize(from_what); end
|
5
|
+
def bark(what); end
|
6
|
+
def feed(what, many = false); end
|
7
|
+
end
|
8
|
+
|
9
|
+
class Animal
|
10
|
+
def initialize(name)
|
11
|
+
@name = name
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.evolutionize(from_what)
|
15
|
+
new("next step from #{from_what}")
|
16
|
+
end
|
17
|
+
|
18
|
+
def bark(what)
|
19
|
+
puts what
|
20
|
+
end
|
21
|
+
|
22
|
+
def feed(what, many = false)
|
23
|
+
emotion = "So yammy #{what}"
|
24
|
+
emotion = [emotion, "I'm full up"].join(", ") if many
|
25
|
+
|
26
|
+
bark emotion
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe Animal do
|
31
|
+
subject { described_class }
|
32
|
+
it { should be_adequack_to AnimalInterface }
|
33
|
+
end
|
34
|
+
|
35
|
+
class Owner
|
36
|
+
|
37
|
+
def initialize(animal)
|
38
|
+
@animal = animal
|
39
|
+
end
|
40
|
+
|
41
|
+
def trick_animal
|
42
|
+
@animal.bark("woof")
|
43
|
+
end
|
44
|
+
|
45
|
+
def enormously_feed_animal
|
46
|
+
@animal.feed("chappy", true)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
describe Owner do
|
52
|
+
let(:animal) { adequack_double double, AnimalInterface }
|
53
|
+
subject { described_class.new animal }
|
54
|
+
|
55
|
+
it "tricks animal" do
|
56
|
+
animal.should_receive(:bark).and_return("barked")
|
57
|
+
expect(subject.trick_animal).to eql "barked"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "feeds animal" do
|
61
|
+
animal.should_receive(:feed).and_return("barked")
|
62
|
+
expect(subject.enormously_feed_animal).to eql "barked"
|
63
|
+
end
|
64
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "adequack"
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: adequack
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ilya Zayats
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-04-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.13'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Be sure that your mocks are adequate
|
56
|
+
email:
|
57
|
+
- somebody32@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- .rspec
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- adequack.gemspec
|
69
|
+
- lib/adequack.rb
|
70
|
+
- lib/adequack/core.rb
|
71
|
+
- lib/adequack/integration/rspec_setup.rb
|
72
|
+
- lib/adequack/proxy.rb
|
73
|
+
- lib/adequack/version.rb
|
74
|
+
- spec/adequack_spec.rb
|
75
|
+
- spec/integration_spec.rb
|
76
|
+
- spec/spec_helper.rb
|
77
|
+
homepage: https://github.com/Somebody32/adequack
|
78
|
+
licenses:
|
79
|
+
- MIT
|
80
|
+
metadata: {}
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 2.0.3
|
98
|
+
signing_key:
|
99
|
+
specification_version: 4
|
100
|
+
summary: Be sure that your mocks are adequate
|
101
|
+
test_files:
|
102
|
+
- spec/adequack_spec.rb
|
103
|
+
- spec/integration_spec.rb
|
104
|
+
- spec/spec_helper.rb
|