better_receive 0.3.0 → 0.4.0
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.
- data/README.md +12 -7
- data/lib/better_receive.rb +8 -2
- data/lib/better_receive/base.rb +47 -0
- data/lib/better_receive/mock.rb +4 -39
- data/lib/better_receive/stub.rb +36 -0
- data/lib/better_receive/version.rb +1 -1
- data/spec/lib/better_receive/mock_spec.rb +11 -11
- data/spec/lib/better_receive/stub_spec.rb +129 -0
- data/spec/lib/better_receive_spec.rb +54 -1
- metadata +6 -2
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
[](https://codeclimate.com/github/se3000/better_receive)
|
1
2
|
# BetterReceive
|
2
3
|
|
3
|
-
|
4
|
+
Test drive new functionality and prevent bugs by asserting objects respond to methods when mocking/stubbing.
|
4
5
|
|
5
6
|
## Installation
|
6
7
|
|
@@ -10,17 +11,22 @@ BetterReceive helps test drive new functionality and prevent bugs by asserting t
|
|
10
11
|
|
11
12
|
|
12
13
|
```ruby
|
14
|
+
|
13
15
|
class Foo; end
|
14
16
|
foo = Foo.new
|
15
17
|
|
16
18
|
foo.better_receive(:bar)
|
19
|
+
# or
|
20
|
+
foo.better_stub(bar: 1, baz: 2)
|
21
|
+
# or
|
22
|
+
Foo.any_instance.better_receive(:bar).with(:wibble)
|
23
|
+
|
17
24
|
```
|
18
|
-
or
|
19
|
-
```ruby
|
20
|
-
Foo.any_instance.better_receive(:bar)
|
21
|
-
```
|
22
25
|
|
23
|
-
|
26
|
+
Any of these situation will raise an error because instances of Foo do not respond to :bar.
|
27
|
+
|
28
|
+
After the initial extra assertion, they continue to act like regular RSpec mocks/stubs.
|
29
|
+
|
24
30
|
|
25
31
|
## Contributing
|
26
32
|
|
@@ -32,7 +38,6 @@ Either situation will raise an error because instances of Foo do not respond to
|
|
32
38
|
|
33
39
|
## To Do
|
34
40
|
|
35
|
-
* #better_stub
|
36
41
|
* support arrity checks with #responds_to
|
37
42
|
* support options other than Ruby 1.9.2+ and RSpec
|
38
43
|
|
data/lib/better_receive.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
require "better_receive/version"
|
2
|
+
require "better_receive/base"
|
2
3
|
require "better_receive/mock"
|
4
|
+
require "better_receive/stub"
|
3
5
|
|
4
6
|
module BetterReceive
|
5
|
-
def better_receive(*args)
|
6
|
-
Mock.new(self).
|
7
|
+
def better_receive(*args, &block)
|
8
|
+
Mock.new(self).assert_with(*args, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def better_stub(*args, &block)
|
12
|
+
Stub.new(self).assert_with(*args, &block)
|
7
13
|
end
|
8
14
|
end
|
9
15
|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module BetterReceive
|
2
|
+
class Base
|
3
|
+
|
4
|
+
def initialize(subject)
|
5
|
+
@subject = subject
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
attr_reader :subject
|
12
|
+
|
13
|
+
def subject_is_any_instance?
|
14
|
+
subject.is_a?(RSpec::Mocks::AnyInstance::Recorder)
|
15
|
+
end
|
16
|
+
|
17
|
+
def respond_to(selector)
|
18
|
+
RSpec::Matchers::BuiltIn::RespondTo.new(selector)
|
19
|
+
end
|
20
|
+
|
21
|
+
def subject_mock_proxy
|
22
|
+
@mock_proxy ||= subject.send(:__mock_proxy)
|
23
|
+
end
|
24
|
+
|
25
|
+
def any_instance_better_expect(selector, options, &block)
|
26
|
+
any_instance_should_respond_to selector
|
27
|
+
any_instance_add_expectation selector, &block
|
28
|
+
end
|
29
|
+
|
30
|
+
def any_instance_should_respond_to(selector)
|
31
|
+
klass = subject.instance_variable_get(:@klass)
|
32
|
+
unless klass.method_defined?(selector)
|
33
|
+
raise "Expected instances of #{klass.name} to respond to :#{selector}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def any_instance_add_expectation(selector, &block)
|
38
|
+
RSpec::Mocks::space.add(subject)
|
39
|
+
|
40
|
+
subject.instance_variable_set(:@expectation_set, true)
|
41
|
+
subject.send(:observe!, selector)
|
42
|
+
|
43
|
+
subject.message_chains.add(selector, expectation_chain(selector, &block))
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/lib/better_receive/mock.rb
CHANGED
@@ -1,13 +1,9 @@
|
|
1
1
|
module BetterReceive
|
2
|
-
class Mock
|
2
|
+
class Mock < Base
|
3
3
|
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
def responds_to_and_receives(selector, options={}, &block)
|
9
|
-
if subject.is_a?(RSpec::Mocks::AnyInstance::Recorder)
|
10
|
-
any_instance_better_receive(selector, options, &block)
|
4
|
+
def assert_with(selector, options={}, &block)
|
5
|
+
if subject_is_any_instance?
|
6
|
+
any_instance_better_expect(selector, options, &block)
|
11
7
|
else
|
12
8
|
subject.should respond_to selector
|
13
9
|
mock_subject_method(selector, options, &block)
|
@@ -17,42 +13,11 @@ module BetterReceive
|
|
17
13
|
|
18
14
|
private
|
19
15
|
|
20
|
-
attr_reader :subject
|
21
|
-
|
22
|
-
def respond_to(selector)
|
23
|
-
RSpec::Matchers::BuiltIn::RespondTo.new(selector)
|
24
|
-
end
|
25
|
-
|
26
16
|
def mock_subject_method(selector, options, &block)
|
27
17
|
location = options[:expected_from] || caller(1)[2]
|
28
18
|
subject_mock_proxy.add_message_expectation(location, selector, options, &block)
|
29
19
|
end
|
30
20
|
|
31
|
-
def subject_mock_proxy
|
32
|
-
@mock_proxy ||= subject.send(:__mock_proxy)
|
33
|
-
end
|
34
|
-
|
35
|
-
def any_instance_better_receive(selector, options, &block)
|
36
|
-
any_instance_should_respond_to selector
|
37
|
-
any_instance_should_receive selector, &block
|
38
|
-
end
|
39
|
-
|
40
|
-
def any_instance_should_respond_to(selector)
|
41
|
-
klass = subject.instance_variable_get(:@klass)
|
42
|
-
unless klass.method_defined?(selector)
|
43
|
-
raise "Expected instances of #{klass.name} to respond to :#{selector}"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def any_instance_should_receive(selector, &block)
|
48
|
-
RSpec::Mocks::space.add(subject)
|
49
|
-
|
50
|
-
subject.instance_variable_set(:@expectation_set, true)
|
51
|
-
subject.send(:observe!, selector)
|
52
|
-
|
53
|
-
subject.message_chains.add(selector, expectation_chain(selector, &block))
|
54
|
-
end
|
55
|
-
|
56
21
|
def expectation_chain(*args)
|
57
22
|
if defined?(RSpec::Mocks::AnyInstance::PositiveExpectationChain)
|
58
23
|
RSpec::Mocks::AnyInstance::PositiveExpectationChain.new(*args)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module BetterReceive
|
2
|
+
class Stub < Base
|
3
|
+
|
4
|
+
def assert_with(selector_or_hash, options={}, &block)
|
5
|
+
if selector_or_hash.is_a?(Hash)
|
6
|
+
selector_or_hash.each do |selector, value|
|
7
|
+
better_stub_method(selector, options, &block).and_return(value)
|
8
|
+
end
|
9
|
+
else
|
10
|
+
better_stub_method(selector_or_hash, options, &block)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def better_stub_method(selector, options, &block)
|
18
|
+
if subject_is_any_instance?
|
19
|
+
any_instance_better_expect(selector, options, &block)
|
20
|
+
else
|
21
|
+
subject.should respond_to selector
|
22
|
+
stub_subject_method(selector, options, &block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def stub_subject_method(selector, options, &block)
|
27
|
+
location = options[:expected_from] || caller(1)[2]
|
28
|
+
subject_mock_proxy.add_stub(location, selector, options, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def expectation_chain(*args)
|
32
|
+
RSpec::Mocks::AnyInstance::StubChain.new(*args)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -1,26 +1,26 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe BetterReceive do
|
3
|
+
describe BetterReceive::Mock do
|
4
4
|
class Foo
|
5
5
|
def bar(baz = nil)
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
|
-
describe "#
|
9
|
+
describe "#assert_with" do
|
10
10
|
let(:foo) { Foo.new }
|
11
11
|
let(:br_mock) { BetterReceive::Mock.new(foo) }
|
12
12
|
|
13
13
|
it "determines whether an object responds to a method" do
|
14
14
|
foo.should_receive(:respond_to?).with(:bar).and_return(true)
|
15
15
|
|
16
|
-
br_mock.
|
16
|
+
br_mock.assert_with :bar
|
17
17
|
|
18
18
|
foo.bar
|
19
19
|
end
|
20
20
|
|
21
|
-
it "raises an error if
|
21
|
+
it "raises an error if the method is not defined" do
|
22
22
|
expect {
|
23
|
-
br_mock.
|
23
|
+
br_mock.assert_with :bar_baz
|
24
24
|
}.to raise_error(RSpec::Expectations::ExpectationNotMetError) { |error|
|
25
25
|
error.message.should =~ /to respond to :bar_baz/
|
26
26
|
}
|
@@ -33,7 +33,7 @@ describe BetterReceive do
|
|
33
33
|
foo.should_receive(:send).with(:__mock_proxy).and_return(mock_proxy)
|
34
34
|
mock_proxy.should_receive(:add_message_expectation)
|
35
35
|
|
36
|
-
br_mock.
|
36
|
+
br_mock.assert_with :bar
|
37
37
|
end
|
38
38
|
|
39
39
|
it "returns an rspec message expectation(responds to additional matchers ('with', 'once'...))" do
|
@@ -41,7 +41,7 @@ describe BetterReceive do
|
|
41
41
|
|
42
42
|
foo.bar
|
43
43
|
|
44
|
-
br_mock.
|
44
|
+
br_mock.assert_with(:bar).with('wibble')
|
45
45
|
|
46
46
|
foo.bar('wibble')
|
47
47
|
end
|
@@ -58,7 +58,7 @@ describe BetterReceive do
|
|
58
58
|
block.should == block_param
|
59
59
|
end
|
60
60
|
|
61
|
-
br_mock.
|
61
|
+
br_mock.assert_with(:bar, passed: true, &block_param)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
@@ -69,7 +69,7 @@ describe BetterReceive do
|
|
69
69
|
context "and the method is called" do
|
70
70
|
it 'does not raise an error' do
|
71
71
|
expect {
|
72
|
-
br_mock.
|
72
|
+
br_mock.assert_with(:bar)
|
73
73
|
foo.bar
|
74
74
|
}.to_not raise_error
|
75
75
|
end
|
@@ -78,7 +78,7 @@ describe BetterReceive do
|
|
78
78
|
context 'and the method is not called' do
|
79
79
|
it 'does raise an error' do
|
80
80
|
expect {
|
81
|
-
br_mock.
|
81
|
+
br_mock.assert_with(:bar)
|
82
82
|
RSpec::Mocks::space.verify_all
|
83
83
|
}.to raise_error(RSpec::Mocks::MockExpectationError) { |error|
|
84
84
|
error.message.should == "Exactly one instance should have received the following message(s) but didn't: bar"
|
@@ -90,7 +90,7 @@ describe BetterReceive do
|
|
90
90
|
context 'when the method is not defined' do
|
91
91
|
it 'raises an error' do
|
92
92
|
expect {
|
93
|
-
br_mock.
|
93
|
+
br_mock.assert_with(:baz)
|
94
94
|
}.to raise_error { |error|
|
95
95
|
error.message.should == "Expected instances of Foo to respond to :baz"
|
96
96
|
}
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BetterReceive::Stub do
|
4
|
+
class Foo
|
5
|
+
def bar(baz = nil)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#assert_with" do
|
10
|
+
let(:foo) { Foo.new }
|
11
|
+
let(:br_stub) { BetterReceive::Stub.new(foo) }
|
12
|
+
|
13
|
+
context "when passed a single selector" do
|
14
|
+
context "when checking responds to" do
|
15
|
+
it "determines whether an object responds to a method" do
|
16
|
+
foo.should_receive(:respond_to?).with(:bar).and_return(true)
|
17
|
+
|
18
|
+
br_stub.assert_with :bar
|
19
|
+
|
20
|
+
foo.bar
|
21
|
+
end
|
22
|
+
|
23
|
+
it "raises an error if the method is not defined" do
|
24
|
+
expect {
|
25
|
+
br_stub.assert_with :bar_baz
|
26
|
+
}.to raise_error(RSpec::Expectations::ExpectationNotMetError) { |error|
|
27
|
+
error.message.should =~ /to respond to :bar_baz/
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when stubbing" do
|
33
|
+
let(:mock_proxy) { double(RSpec::Mocks::Proxy).as_null_object }
|
34
|
+
let(:block_param) { Proc.new {} }
|
35
|
+
let(:options) { {passed: true} }
|
36
|
+
|
37
|
+
it "creates a mock proxy and adds an expectation to it" do
|
38
|
+
foo.should_receive(:send).with(:__mock_proxy).and_return(mock_proxy)
|
39
|
+
mock_proxy.should_receive(:add_stub)
|
40
|
+
|
41
|
+
br_stub.assert_with :bar
|
42
|
+
end
|
43
|
+
|
44
|
+
it "returns an rspec message expectation(responds to additional matchers ('with', 'once'...))" do
|
45
|
+
br_stub.assert_with(:bar).should be_a RSpec::Mocks::MessageExpectation
|
46
|
+
|
47
|
+
|
48
|
+
br_stub.assert_with(:bar).with('wibble')
|
49
|
+
end
|
50
|
+
|
51
|
+
it "passes all arguments through to the mock_proxy" do
|
52
|
+
foo.should_receive(:send).with(:__mock_proxy).and_return(mock_proxy)
|
53
|
+
mock_proxy.should_receive(:add_stub) do |*args, &block|
|
54
|
+
args[1].should == :bar
|
55
|
+
args[2].should == options
|
56
|
+
block.should == block_param
|
57
|
+
end
|
58
|
+
|
59
|
+
br_stub.assert_with(:bar, passed: true, &block_param)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "returns the value passed in the block" do
|
63
|
+
br_stub.assert_with(:bar) { :baz }
|
64
|
+
|
65
|
+
foo.bar.should == :baz
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when passed a hash" do
|
71
|
+
class Foo
|
72
|
+
def extra; end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "and checking responds to" do
|
76
|
+
it "determines whether an object responds to a method" do
|
77
|
+
params = {bar: '1', extra: '2'}
|
78
|
+
|
79
|
+
foo.should_receive(:respond_to?).with(:bar).and_return(true)
|
80
|
+
foo.should_receive(:respond_to?).with(:extra).and_return(true)
|
81
|
+
|
82
|
+
br_stub.assert_with params
|
83
|
+
end
|
84
|
+
|
85
|
+
it "raises an error if the method is not defined" do
|
86
|
+
params = {bar: '1', baz: '2'}
|
87
|
+
|
88
|
+
expect{
|
89
|
+
br_stub.assert_with params
|
90
|
+
}.to raise_error(RSpec::Expectations::ExpectationNotMetError) { |error|
|
91
|
+
error.message.should =~ /to respond to :baz/
|
92
|
+
}
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "and stubbing" do
|
97
|
+
it 'stubs out each method' do
|
98
|
+
params = {bar: '1', extra: '2'}
|
99
|
+
br_stub.assert_with params
|
100
|
+
|
101
|
+
foo.bar.should == '1'
|
102
|
+
foo.extra.should == '2'
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "on .any_instance" do
|
108
|
+
let(:br_stub) { BetterReceive::Stub.new(Foo.any_instance) }
|
109
|
+
|
110
|
+
context "when the method is defined" do
|
111
|
+
it 'stubs the method out' do
|
112
|
+
br_stub.assert_with(:bar).and_return(:whatever)
|
113
|
+
|
114
|
+
foo.bar.should == :whatever
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'when the method is not defined' do
|
119
|
+
it 'raises an error' do
|
120
|
+
expect {
|
121
|
+
br_stub.assert_with(:baz)
|
122
|
+
}.to raise_error { |error|
|
123
|
+
error.message.should == "Expected instances of Foo to respond to :baz"
|
124
|
+
}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -18,9 +18,62 @@ describe BetterReceive do
|
|
18
18
|
it "checks that the object responds to the method and that the method is called" do
|
19
19
|
BetterReceive::Mock.stub(:new).with(foo).and_return(br_instance)
|
20
20
|
|
21
|
-
br_instance.should_receive(:
|
21
|
+
br_instance.should_receive(:assert_with).with(:bar)
|
22
22
|
|
23
23
|
foo.better_receive(:bar)
|
24
24
|
end
|
25
|
+
|
26
|
+
it "returns an RSpec expectation object" do
|
27
|
+
foo.better_receive(:bar).should be_a RSpec::Mocks::MessageExpectation
|
28
|
+
|
29
|
+
foo.bar
|
30
|
+
|
31
|
+
|
32
|
+
foo.better_receive(:bar).with('wibble')
|
33
|
+
|
34
|
+
foo.bar('wibble')
|
35
|
+
end
|
36
|
+
|
37
|
+
it "returns the value of the block passed in" do
|
38
|
+
foo.better_receive(:bar) { :baz }
|
39
|
+
|
40
|
+
foo.bar.should == :baz
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#better_stub" do
|
45
|
+
let(:foo) { Foo.new }
|
46
|
+
let(:br_instance) { double(BetterReceive::Stub).as_null_object }
|
47
|
+
|
48
|
+
it "passes the object being stubbed into a new BetterReceive::Stub instance" do
|
49
|
+
BetterReceive::Stub.should_receive(:new).with(foo).and_return(br_instance)
|
50
|
+
|
51
|
+
foo.better_stub(:bar)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "checks that the object responds to the method and that the method is called" do
|
55
|
+
BetterReceive::Stub.stub(:new).with(foo).and_return(br_instance)
|
56
|
+
|
57
|
+
br_instance.should_receive(:assert_with).with(:bar)
|
58
|
+
|
59
|
+
foo.better_stub(:bar)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "returns an RSpec expectation object" do
|
63
|
+
foo.better_stub(:bar).should be_a RSpec::Mocks::MessageExpectation
|
64
|
+
|
65
|
+
foo.bar
|
66
|
+
|
67
|
+
|
68
|
+
foo.better_stub(:bar).with('wibble')
|
69
|
+
|
70
|
+
foo.bar('wibble')
|
71
|
+
end
|
72
|
+
|
73
|
+
it "returns the value of the block passed in" do
|
74
|
+
foo.better_stub(:bar) { :baz }
|
75
|
+
|
76
|
+
foo.bar.should == :baz
|
77
|
+
end
|
25
78
|
end
|
26
79
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: better_receive
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-01-
|
13
|
+
date: 2013-01-28 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -77,9 +77,12 @@ files:
|
|
77
77
|
- Rakefile
|
78
78
|
- better_receive.gemspec
|
79
79
|
- lib/better_receive.rb
|
80
|
+
- lib/better_receive/base.rb
|
80
81
|
- lib/better_receive/mock.rb
|
82
|
+
- lib/better_receive/stub.rb
|
81
83
|
- lib/better_receive/version.rb
|
82
84
|
- spec/lib/better_receive/mock_spec.rb
|
85
|
+
- spec/lib/better_receive/stub_spec.rb
|
83
86
|
- spec/lib/better_receive_spec.rb
|
84
87
|
- spec/spec_helper.rb
|
85
88
|
homepage: http://github.com/se3000/better_receive
|
@@ -108,5 +111,6 @@ specification_version: 3
|
|
108
111
|
summary: A more assertive mock.
|
109
112
|
test_files:
|
110
113
|
- spec/lib/better_receive/mock_spec.rb
|
114
|
+
- spec/lib/better_receive/stub_spec.rb
|
111
115
|
- spec/lib/better_receive_spec.rb
|
112
116
|
- spec/spec_helper.rb
|