spy 0.0.1 → 0.1.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/.yardopts +1 -0
- data/Gemfile +2 -0
- data/README.md +90 -44
- data/lib/spy.rb +85 -207
- data/lib/spy/agency.rb +65 -0
- data/lib/spy/constant.rb +67 -0
- data/lib/spy/core_ext/marshal.rb +28 -0
- data/lib/spy/double.rb +1 -1
- data/lib/spy/nest.rb +45 -0
- data/lib/spy/subroutine.rb +239 -0
- data/lib/spy/version.rb +2 -2
- data/spec/spec_helper.rb +4 -2
- data/spec/spy/and_call_original_spec.rb +1 -1
- data/spec/spy/and_yield_spec.rb +23 -14
- data/spec/spy/hash_excluding_matcher_spec.rb +55 -59
- data/spec/spy/hash_including_matcher_spec.rb +69 -73
- data/spec/spy/mock_spec.rb +585 -589
- data/spec/spy/mutate_const_spec.rb +407 -367
- data/spec/spy/partial_mock_spec.rb +106 -162
- data/spec/spy/passing_argument_matchers_spec.rb +134 -136
- data/spec/spy/serialization_spec.rb +80 -74
- data/spec/spy/stub_implementation_spec.rb +14 -12
- data/spec/spy/stub_spec.rb +12 -12
- data/spec/spy/test_double_spec.rb +38 -41
- data/spy.gemspec +2 -1
- data/test/integration/test_constant_spying.rb +58 -0
- data/test/integration/test_subroutine_spying.rb +40 -0
- data/test/spy/test_double.rb +1 -1
- data/test/spy/test_subroutine.rb +191 -0
- data/test/support/pen.rb +50 -0
- data/test/test_helper.rb +4 -0
- metadata +33 -9
- data/TODO.md +0 -8
- data/lib/spy/dsl.rb +0 -7
- data/spec/spy/multiple_return_value_spec.rb +0 -119
- data/test/test_spy.rb +0 -258
data/lib/spy/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "0.0
|
1
|
+
module Spy
|
2
|
+
VERSION = "0.1.0"
|
3
3
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
require "rspec/
|
1
|
+
require "rspec/core"
|
2
|
+
require "rspec/matchers"
|
3
|
+
require "rspec/expectations"
|
2
4
|
require "spy"
|
3
5
|
require "pry"
|
4
6
|
require "pry-nav"
|
@@ -16,7 +18,7 @@ RSpec.configure do |config|
|
|
16
18
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
17
19
|
config.filter_run_including :focus
|
18
20
|
config.filter_run_excluding :broken => true
|
19
|
-
|
21
|
+
config.mock_with :absolutely_nothing
|
20
22
|
|
21
23
|
config.expect_with :rspec do |expectations|
|
22
24
|
expectations.syntax = :expect
|
@@ -133,7 +133,7 @@ describe "and_call_through" do
|
|
133
133
|
end
|
134
134
|
|
135
135
|
it 'raises an error on invocation if method_missing does not handle the message' do
|
136
|
-
Spy.new(instance, :not_a_handled_message).hook(force: true).and_call_through
|
136
|
+
Spy::Subroutine.new(instance, :not_a_handled_message).hook(force: true).and_call_through
|
137
137
|
|
138
138
|
# Note: it should raise a NoMethodError (and usually does), but
|
139
139
|
# due to a weird rspec-expectations issue (see #183) it sometimes
|
data/spec/spy/and_yield_spec.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe "Spy" do
|
4
4
|
|
5
|
-
|
5
|
+
class Foo
|
6
|
+
def method_that_accepts_a_block(&block)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:obj) { Foo.new }
|
6
11
|
|
7
12
|
describe "#and_yield" do
|
8
13
|
context "with eval context as block argument" do
|
@@ -40,30 +45,32 @@ describe RSpec::Mocks::Mock do
|
|
40
45
|
|
41
46
|
it "passes when expectations set on the eval context are met" do
|
42
47
|
configured_eval_context = nil
|
48
|
+
context_foo_spy = nil
|
43
49
|
Spy.on(obj, :method_that_accepts_a_block).and_yield do |eval_context|
|
44
50
|
configured_eval_context = eval_context
|
45
|
-
|
51
|
+
context_foo_spy = Spy::Subroutine.new(configured_eval_context, :foo).hook(force: true)
|
46
52
|
end
|
47
53
|
|
48
54
|
obj.method_that_accepts_a_block do
|
49
55
|
foo
|
50
56
|
end
|
51
57
|
|
52
|
-
|
58
|
+
expect(context_foo_spy).to have_been_called
|
53
59
|
end
|
54
60
|
|
55
61
|
it "fails when expectations set on the eval context are not met" do
|
56
62
|
configured_eval_context = nil
|
63
|
+
context_foo_spy = nil
|
57
64
|
Spy.on(obj, :method_that_accepts_a_block).and_yield do |eval_context|
|
58
65
|
configured_eval_context = eval_context
|
59
|
-
|
66
|
+
context_foo_spy = Spy::Subroutine.new(configured_eval_context, :foo).hook(force: true)
|
60
67
|
end
|
61
68
|
|
62
69
|
obj.method_that_accepts_a_block do
|
63
70
|
# foo is not called here
|
64
71
|
end
|
65
72
|
|
66
|
-
expect
|
73
|
+
expect(context_foo_spy).to_not have_been_called
|
67
74
|
end
|
68
75
|
|
69
76
|
end
|
@@ -73,10 +80,11 @@ describe RSpec::Mocks::Mock do
|
|
73
80
|
it "passes when expectations set on the eval context and yielded arguments are met" do
|
74
81
|
configured_eval_context = nil
|
75
82
|
yielded_arg = Object.new
|
83
|
+
context_foo_spy = nil
|
76
84
|
Spy.on(obj, :method_that_accepts_a_block).and_yield(yielded_arg) do |eval_context|
|
77
85
|
configured_eval_context = eval_context
|
78
|
-
|
79
|
-
|
86
|
+
context_foo_spy = Spy::Subroutine.new(configured_eval_context, :foo).hook(force: true)
|
87
|
+
Spy::Subroutine.new(yielded_arg, :bar).hook(force: true)
|
80
88
|
end
|
81
89
|
|
82
90
|
obj.method_that_accepts_a_block do |obj|
|
@@ -84,17 +92,18 @@ describe RSpec::Mocks::Mock do
|
|
84
92
|
foo
|
85
93
|
end
|
86
94
|
|
87
|
-
|
88
|
-
yielded_arg.
|
95
|
+
expect(context_foo_spy).to have_been_called
|
96
|
+
expect(Spy.get(yielded_arg, :bar)).to have_been_called
|
89
97
|
end
|
90
98
|
|
91
99
|
it "fails when expectations set on the eval context and yielded arguments are not met" do
|
92
100
|
configured_eval_context = nil
|
93
101
|
yielded_arg = Object.new
|
102
|
+
context_foo_spy = nil
|
94
103
|
Spy.on(obj, :method_that_accepts_a_block).and_yield(yielded_arg) do |eval_context|
|
95
104
|
configured_eval_context = eval_context
|
96
|
-
|
97
|
-
|
105
|
+
context_foo_spy = Spy::Subroutine.new(configured_eval_context, :foo).hook(force: true)
|
106
|
+
Spy::Subroutine.new(yielded_arg, :bar).hook(force: true)
|
98
107
|
end
|
99
108
|
|
100
109
|
obj.method_that_accepts_a_block do |obj|
|
@@ -102,8 +111,8 @@ describe RSpec::Mocks::Mock do
|
|
102
111
|
# foo is not called here
|
103
112
|
end
|
104
113
|
|
105
|
-
expect
|
106
|
-
expect
|
114
|
+
expect(context_foo_spy).to_not have_been_called
|
115
|
+
expect(Spy.get(yielded_arg, :bar)).to_not have_been_called
|
107
116
|
end
|
108
117
|
|
109
118
|
end
|
@@ -1,66 +1,62 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
module
|
4
|
-
|
5
|
-
module ArgumentMatchers
|
6
|
-
describe HashExcludingMatcher do
|
7
|
-
|
8
|
-
it "describes itself properly" do
|
9
|
-
expect(HashExcludingMatcher.new(:a => 5).description).to eq "hash_not_including(:a=>5)"
|
10
|
-
end
|
3
|
+
module Spy
|
4
|
+
describe "Hash excluding matchers", broken: true do
|
11
5
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
6
|
+
it "describes itself properly" do
|
7
|
+
expect(HashExcludingMatcher.new(:a => 5).description).to eq "hash_not_including(:a=>5)"
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "passing" do
|
11
|
+
it "matches a hash without the specified key" do
|
12
|
+
expect(hash_not_including(:c)).to eq({:a => 1, :b => 2})
|
13
|
+
end
|
14
|
+
|
15
|
+
it "matches a hash with the specified key, but different value" do
|
16
|
+
expect(hash_not_including(:b => 3)).to eq({:a => 1, :b => 2})
|
17
|
+
end
|
18
|
+
|
19
|
+
it "matches a hash without the specified key, given as anything()" do
|
20
|
+
expect(hash_not_including(:c => anything)).to eq({:a => 1, :b => 2})
|
21
|
+
end
|
22
|
+
|
23
|
+
it "matches an empty hash" do
|
24
|
+
expect(hash_not_including(:a)).to eq({})
|
25
|
+
end
|
26
|
+
|
27
|
+
it "matches a hash without any of the specified keys" do
|
28
|
+
expect(hash_not_including(:a, :b, :c)).to eq(:d => 7)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "failing" do
|
34
|
+
it "does not match a non-hash" do
|
35
|
+
expect(hash_not_including(:a => 1)).not_to eq 1
|
36
|
+
end
|
37
|
+
|
38
|
+
it "does not match a hash with a specified key" do
|
39
|
+
expect(hash_not_including(:b)).not_to eq(:b => 2)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "does not match a hash with the specified key/value pair" do
|
43
|
+
expect(hash_not_including(:b => 2)).not_to eq(:a => 1, :b => 2)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "does not match a hash with the specified key" do
|
47
|
+
expect(hash_not_including(:a, :b => 3)).not_to eq(:a => 1, :b => 2)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "does not match a hash with one of the specified keys" do
|
51
|
+
expect(hash_not_including(:a, :b)).not_to eq(:b => 2)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "does not match a hash with some of the specified keys" do
|
55
|
+
expect(hash_not_including(:a, :b, :c)).not_to eq(:a => 1, :b => 2)
|
56
|
+
end
|
24
57
|
|
25
|
-
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
it "matches a hash without any of the specified keys" do
|
30
|
-
expect(hash_not_including(:a, :b, :c)).to eq(:d => 7)
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
describe "failing" do
|
36
|
-
it "does not match a non-hash" do
|
37
|
-
expect(hash_not_including(:a => 1)).not_to eq 1
|
38
|
-
end
|
39
|
-
|
40
|
-
it "does not match a hash with a specified key" do
|
41
|
-
expect(hash_not_including(:b)).not_to eq(:b => 2)
|
42
|
-
end
|
43
|
-
|
44
|
-
it "does not match a hash with the specified key/value pair" do
|
45
|
-
expect(hash_not_including(:b => 2)).not_to eq(:a => 1, :b => 2)
|
46
|
-
end
|
47
|
-
|
48
|
-
it "does not match a hash with the specified key" do
|
49
|
-
expect(hash_not_including(:a, :b => 3)).not_to eq(:a => 1, :b => 2)
|
50
|
-
end
|
51
|
-
|
52
|
-
it "does not match a hash with one of the specified keys" do
|
53
|
-
expect(hash_not_including(:a, :b)).not_to eq(:b => 2)
|
54
|
-
end
|
55
|
-
|
56
|
-
it "does not match a hash with some of the specified keys" do
|
57
|
-
expect(hash_not_including(:a, :b, :c)).not_to eq(:a => 1, :b => 2)
|
58
|
-
end
|
59
|
-
|
60
|
-
it "does not match a hash with one key/value pair included" do
|
61
|
-
expect(hash_not_including(:a, :b, :c, :d => 7)).not_to eq(:d => 7)
|
62
|
-
end
|
63
|
-
end
|
58
|
+
it "does not match a hash with one key/value pair included" do
|
59
|
+
expect(hash_not_including(:a, :b, :c, :d => 7)).not_to eq(:d => 7)
|
64
60
|
end
|
65
61
|
end
|
66
62
|
end
|
@@ -1,90 +1,86 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
module
|
4
|
-
|
5
|
-
module ArgumentMatchers
|
6
|
-
describe HashIncludingMatcher do
|
3
|
+
module Spy
|
4
|
+
describe "Hash including matchers", broken: true do
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
it "describes itself properly" do
|
7
|
+
expect(HashIncludingMatcher.new(:a => 1).description).to eq "hash_including(:a=>1)"
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "passing" do
|
11
|
+
it "matches the same hash" do
|
12
|
+
expect(hash_including(:a => 1)).to eq({:a => 1})
|
13
|
+
end
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
describe "when matching against other matchers" do
|
22
|
-
it "matches an int against anything()" do
|
23
|
-
expect(hash_including(:a => anything, :b => 2)).to eq({:a => 1, :b => 2})
|
24
|
-
end
|
25
|
-
|
26
|
-
it "matches a string against anything()" do
|
27
|
-
expect(hash_including(:a => anything, :b => 2)).to eq({:a => "1", :b => 2})
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
describe "when passed only keys or keys mixed with key/value pairs" do
|
32
|
-
it "matches if the key is present" do
|
33
|
-
expect(hash_including(:a)).to eq({:a => 1, :b => 2})
|
34
|
-
end
|
35
|
-
|
36
|
-
it "matches if more keys are present" do
|
37
|
-
expect(hash_including(:a, :b)).to eq({:a => 1, :b => 2, :c => 3})
|
38
|
-
end
|
39
|
-
|
40
|
-
it "matches a string against a given key" do
|
41
|
-
expect(hash_including(:a)).to eq({:a => "1", :b => 2})
|
42
|
-
end
|
43
|
-
|
44
|
-
it "matches if passed one key and one key/value pair" do
|
45
|
-
expect(hash_including(:a, :b => 2)).to eq({:a => 1, :b => 2})
|
46
|
-
end
|
47
|
-
|
48
|
-
it "matches if passed many keys and one key/value pair" do
|
49
|
-
expect(hash_including(:a, :b, :c => 3)).to eq({:a => 1, :b => 2, :c => 3, :d => 4})
|
50
|
-
end
|
51
|
-
|
52
|
-
it "matches if passed many keys and many key/value pairs" do
|
53
|
-
expect(hash_including(:a, :b, :c => 3, :e => 5)).to eq({:a => 1, :b => 2, :c => 3, :d => 4, :e => 5})
|
54
|
-
end
|
55
|
-
end
|
15
|
+
it "matches a hash with extra stuff" do
|
16
|
+
expect(hash_including(:a => 1)).to eq({:a => 1, :b => 2})
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "when matching against other matchers" do
|
20
|
+
it "matches an int against anything()" do
|
21
|
+
expect(hash_including(:a => anything, :b => 2)).to eq({:a => 1, :b => 2})
|
56
22
|
end
|
57
23
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
24
|
+
it "matches a string against anything()" do
|
25
|
+
expect(hash_including(:a => anything, :b => 2)).to eq({:a => "1", :b => 2})
|
26
|
+
end
|
27
|
+
end
|
62
28
|
|
63
|
-
|
64
|
-
|
65
|
-
|
29
|
+
describe "when passed only keys or keys mixed with key/value pairs" do
|
30
|
+
it "matches if the key is present" do
|
31
|
+
expect(hash_including(:a)).to eq({:a => 1, :b => 2})
|
32
|
+
end
|
66
33
|
|
67
|
-
|
68
|
-
|
69
|
-
|
34
|
+
it "matches if more keys are present" do
|
35
|
+
expect(hash_including(:a, :b)).to eq({:a => 1, :b => 2, :c => 3})
|
36
|
+
end
|
70
37
|
|
71
|
-
|
72
|
-
|
73
|
-
|
38
|
+
it "matches a string against a given key" do
|
39
|
+
expect(hash_including(:a)).to eq({:a => "1", :b => 2})
|
40
|
+
end
|
74
41
|
|
75
|
-
|
76
|
-
|
77
|
-
|
42
|
+
it "matches if passed one key and one key/value pair" do
|
43
|
+
expect(hash_including(:a, :b => 2)).to eq({:a => 1, :b => 2})
|
44
|
+
end
|
78
45
|
|
79
|
-
|
80
|
-
|
81
|
-
|
46
|
+
it "matches if passed many keys and one key/value pair" do
|
47
|
+
expect(hash_including(:a, :b, :c => 3)).to eq({:a => 1, :b => 2, :c => 3, :d => 4})
|
48
|
+
end
|
82
49
|
|
83
|
-
|
84
|
-
|
85
|
-
end
|
50
|
+
it "matches if passed many keys and many key/value pairs" do
|
51
|
+
expect(hash_including(:a, :b, :c => 3, :e => 5)).to eq({:a => 1, :b => 2, :c => 3, :d => 4, :e => 5})
|
86
52
|
end
|
87
53
|
end
|
88
54
|
end
|
55
|
+
|
56
|
+
describe "failing" do
|
57
|
+
it "does not match a non-hash" do
|
58
|
+
expect(hash_including(:a => 1)).not_to eq 1
|
59
|
+
end
|
60
|
+
|
61
|
+
it "does not match a hash with a missing key" do
|
62
|
+
expect(hash_including(:a => 1)).not_to eq(:b => 2)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "does not match a hash with a missing key" do
|
66
|
+
expect(hash_including(:a)).not_to eq(:b => 2)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "does not match an empty hash with a given key" do
|
70
|
+
expect(hash_including(:a)).not_to eq({})
|
71
|
+
end
|
72
|
+
|
73
|
+
it "does not match a hash with a missing key when one pair is matching" do
|
74
|
+
expect(hash_including(:a, :b => 2)).not_to eq(:b => 2)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "does not match a hash with an incorrect value" do
|
78
|
+
expect(hash_including(:a => 1, :b => 2)).not_to eq(:a => 1, :b => 3)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "does not match when values are nil but keys are different" do
|
82
|
+
expect(hash_including(:a => nil)).not_to eq(:b => nil)
|
83
|
+
end
|
84
|
+
end
|
89
85
|
end
|
90
86
|
end
|
data/spec/spy/mock_spec.rb
CHANGED
@@ -1,734 +1,730 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
before(:each) { @double = double("test double") }
|
7
|
-
after(:each) { @double.rspec_reset }
|
8
|
-
|
9
|
-
it "has method_missing as private" do
|
10
|
-
expect(RSpec::Mocks::Mock.private_instance_methods).to include_method(:method_missing)
|
11
|
-
end
|
12
|
-
|
13
|
-
it "does not respond_to? method_missing (because it's private)" do
|
14
|
-
expect(RSpec::Mocks::Mock.new).not_to respond_to(:method_missing)
|
15
|
-
end
|
3
|
+
module Spy
|
4
|
+
describe Double do
|
5
|
+
before(:each) { @double = Spy.double("test double") }
|
16
6
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
@double.rspec_verify
|
21
|
-
violated
|
22
|
-
rescue RSpec::Mocks::MockExpectationError => e
|
23
|
-
# NOTE - this regexp ended w/ $, but jruby adds extra info at the end of the line
|
24
|
-
expect(e.backtrace[0]).to match(/#{File.basename(__FILE__)}:#{expected_error_line}/)
|
25
|
-
end
|
26
|
-
end
|
7
|
+
it "has method_missing as private" do
|
8
|
+
expect(Spy.double("stuff").private_instance_methods).to include_method(:method_missing)
|
9
|
+
end
|
27
10
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
begin
|
32
|
-
@double.rspec_verify
|
33
|
-
violated
|
34
|
-
rescue RSpec::Mocks::MockExpectationError => e
|
35
|
-
# NOTE - this regexp ended w/ $, but jruby adds extra info at the end of the line
|
36
|
-
expect(e.backtrace[0]).to match(/#{File.basename(__FILE__)}:#{expected_error_line}/)
|
37
|
-
end
|
38
|
-
end
|
11
|
+
it "does not respond_to? method_missing (because it's private)" do
|
12
|
+
expect(Spy.double("stuff")).not_to respond_to(:method_missing)
|
13
|
+
end
|
39
14
|
|
40
|
-
|
41
|
-
|
15
|
+
it "reports line number of expectation of unreceived message" do
|
16
|
+
expected_error_line = __LINE__; @double.should_receive(:wont_happen).with("x", 3)
|
17
|
+
begin
|
42
18
|
@double.rspec_verify
|
19
|
+
violated
|
20
|
+
rescue RSpec::Mocks::MockExpectationError => e
|
21
|
+
# NOTE - this regexp ended w/ $, but jruby adds extra info at the end of the line
|
22
|
+
expect(e.backtrace[0]).to match(/#{File.basename(__FILE__)}:#{expected_error_line}/)
|
43
23
|
end
|
24
|
+
end
|
44
25
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
@double.should_not_receive(:do_something).and_return(1)
|
50
|
-
end
|
51
|
-
|
52
|
-
it "passes when receiving message specified as not to be received with different args" do
|
53
|
-
@double.should_not_receive(:message).with("unwanted text")
|
54
|
-
@double.should_receive(:message).with("other text")
|
55
|
-
@double.message "other text"
|
26
|
+
it "reports line number of expectation of unreceived message after #should_receive after similar stub" do
|
27
|
+
Spy.on(@double, :wont_happen)
|
28
|
+
expected_error_line = __LINE__; @double.should_receive(:wont_happen).with("x", 3)
|
29
|
+
begin
|
56
30
|
@double.rspec_verify
|
31
|
+
violated
|
32
|
+
rescue RSpec::Mocks::MockExpectationError => e
|
33
|
+
# NOTE - this regexp ended w/ $, but jruby adds extra info at the end of the line
|
34
|
+
expect(e.backtrace[0]).to match(/#{File.basename(__FILE__)}:#{expected_error_line}/)
|
57
35
|
end
|
36
|
+
end
|
58
37
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
violated
|
64
|
-
}.to raise_error(
|
65
|
-
RSpec::Mocks::MockExpectationError,
|
66
|
-
%Q|(Double "test double").not_expected(no args)\n expected: 0 times\n received: 1 time|
|
67
|
-
)
|
68
|
-
end
|
69
|
-
|
70
|
-
it "fails when receiving message specified as not to be received with args" do
|
71
|
-
@double.should_not_receive(:not_expected).with("unexpected text")
|
72
|
-
expect {
|
73
|
-
@double.not_expected("unexpected text")
|
74
|
-
violated
|
75
|
-
}.to raise_error(
|
76
|
-
RSpec::Mocks::MockExpectationError,
|
77
|
-
%Q|(Double "test double").not_expected("unexpected text")\n expected: 0 times\n received: 1 time|
|
78
|
-
)
|
79
|
-
end
|
38
|
+
it "passes when not receiving message specified as not to be received" do
|
39
|
+
@double.should_not_receive(:not_expected)
|
40
|
+
@double.rspec_verify
|
41
|
+
end
|
80
42
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
@double.rspec_verify
|
85
|
-
end
|
43
|
+
it "warns when should_not_receive is followed by and_return" do
|
44
|
+
RSpec::Mocks.should_receive(:warn_deprecation).
|
45
|
+
with(/`and_return` with `should_not_receive` is deprecated/)
|
86
46
|
|
87
|
-
|
88
|
-
|
89
|
-
expect(@double.something("a","b","c")).to eq "cba"
|
90
|
-
@double.rspec_verify
|
91
|
-
end
|
47
|
+
@double.should_not_receive(:do_something).and_return(1)
|
48
|
+
end
|
92
49
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
50
|
+
it "passes when receiving message specified as not to be received with different args" do
|
51
|
+
@double.should_not_receive(:message).with("unwanted text")
|
52
|
+
@double.should_receive(:message).with("other text")
|
53
|
+
@double.message "other text"
|
54
|
+
@double.rspec_verify
|
55
|
+
end
|
98
56
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
57
|
+
it "fails when receiving message specified as not to be received" do
|
58
|
+
@double.should_not_receive(:not_expected)
|
59
|
+
expect {
|
60
|
+
@double.not_expected
|
61
|
+
violated
|
62
|
+
}.to raise_error(
|
63
|
+
RSpec::Mocks::MockExpectationError,
|
64
|
+
%Q|(Double "test double").not_expected(no args)\n expected: 0 times\n received: 1 time|
|
65
|
+
)
|
66
|
+
end
|
105
67
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
@double.
|
110
|
-
|
68
|
+
it "fails when receiving message specified as not to be received with args" do
|
69
|
+
@double.should_not_receive(:not_expected).with("unexpected text")
|
70
|
+
expect {
|
71
|
+
@double.not_expected("unexpected text")
|
72
|
+
violated
|
73
|
+
}.to raise_error(
|
74
|
+
RSpec::Mocks::MockExpectationError,
|
75
|
+
%Q|(Double "test double").not_expected("unexpected text")\n expected: 0 times\n received: 1 time|
|
76
|
+
)
|
77
|
+
end
|
111
78
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (\"a\", \"b\", \"c\")\n got: (\"a\", \"d\", \"c\")")
|
118
|
-
end
|
79
|
+
it "passes when receiving message specified as not to be received with wrong args" do
|
80
|
+
@double.should_not_receive(:not_expected).with("unexpected text")
|
81
|
+
@double.not_expected "really unexpected text"
|
82
|
+
@double.rspec_verify
|
83
|
+
end
|
119
84
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
@double.something("a","b","c")
|
126
|
-
@double.something("z","x","g")
|
127
|
-
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (\"z\", \"x\", \"c\")\n got: (\"z\", \"x\", \"g\")")
|
128
|
-
end
|
129
|
-
end
|
85
|
+
it "allows block to calculate return values" do
|
86
|
+
@double.should_receive(:something).with("a","b","c").and_return { |a,b,c| c+b+a }
|
87
|
+
expect(@double.something("a","b","c")).to eq "cba"
|
88
|
+
@double.rspec_verify
|
89
|
+
end
|
130
90
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
@double.rspec_verify
|
137
|
-
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (\"a\", \"b\", \"c\")\n got: (\"a\", \"d\", \"c\")")
|
138
|
-
end
|
91
|
+
it "allows parameter as return value" do
|
92
|
+
@double.should_receive(:something).with("a","b","c").and_return("booh")
|
93
|
+
expect(@double.something("a","b","c")).to eq "booh"
|
94
|
+
@double.rspec_verify
|
95
|
+
end
|
139
96
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (\"a\", \"b\", \"c\")\n got: (\"a\", \"d\", \"c\")")
|
147
|
-
end
|
97
|
+
it "returns the previously stubbed value if no return value is set" do
|
98
|
+
Spy.on(@double, :something).with("a","b","c").and_return(:stubbed_value)
|
99
|
+
@double.should_receive(:something).with("a","b","c")
|
100
|
+
expect(@double.something("a","b","c")).to eq :stubbed_value
|
101
|
+
@double.rspec_verify
|
102
|
+
end
|
148
103
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
104
|
+
it "returns nil if no return value is set and there is no previously stubbed value" do
|
105
|
+
@double.should_receive(:something).with("a","b","c")
|
106
|
+
expect(@double.something("a","b","c")).to be_nil
|
107
|
+
@double.rspec_verify
|
108
|
+
end
|
153
109
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
110
|
+
it "raises exception if args don't match when method called" do
|
111
|
+
@double.should_receive(:something).with("a","b","c").and_return("booh")
|
112
|
+
expect {
|
113
|
+
@double.something("a","d","c")
|
114
|
+
violated
|
115
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (\"a\", \"b\", \"c\")\n got: (\"a\", \"d\", \"c\")")
|
116
|
+
end
|
160
117
|
|
161
|
-
|
118
|
+
describe "even when a similar expectation with different arguments exist" do
|
119
|
+
it "raises exception if args don't match when method called, correctly reporting the offending arguments" do
|
120
|
+
@double.should_receive(:something).with("a","b","c").once
|
121
|
+
@double.should_receive(:something).with("z","x","c").once
|
162
122
|
expect {
|
163
123
|
@double.something("a","b","c")
|
164
|
-
|
165
|
-
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received
|
124
|
+
@double.something("z","x","g")
|
125
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (\"z\", \"x\", \"c\")\n got: (\"z\", \"x\", \"g\")")
|
166
126
|
end
|
127
|
+
end
|
167
128
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
end
|
174
|
-
expect(@double.something("a", "b")).to eq "booh"
|
129
|
+
it "raises exception if args don't match when method called even when the method is stubbed" do
|
130
|
+
Spy.on(@double, :something)
|
131
|
+
@double.should_receive(:something).with("a","b","c")
|
132
|
+
expect {
|
133
|
+
@double.something("a","d","c")
|
175
134
|
@double.rspec_verify
|
176
|
-
|
135
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (\"a\", \"b\", \"c\")\n got: (\"a\", \"d\", \"c\")")
|
136
|
+
end
|
177
137
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
138
|
+
it "raises exception if args don't match when method called even when using null_object" do
|
139
|
+
@double = double("test double").as_null_object
|
140
|
+
@double.should_receive(:something).with("a","b","c")
|
141
|
+
expect {
|
142
|
+
@double.something("a","d","c")
|
143
|
+
@double.rspec_verify
|
144
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (\"a\", \"b\", \"c\")\n got: (\"a\", \"d\", \"c\")")
|
145
|
+
end
|
146
|
+
|
147
|
+
describe 'with a method that has a default argument' do
|
148
|
+
it "raises an exception if the arguments don't match when the method is called, correctly reporting the offending arguments" do
|
149
|
+
def @double.method_with_default_argument(arg={}); end
|
150
|
+
@double.should_receive(:method_with_default_argument).with({})
|
182
151
|
|
183
152
|
expect {
|
184
|
-
@double.
|
185
|
-
|
153
|
+
@double.method_with_default_argument(nil)
|
154
|
+
@double.rspec_verify
|
155
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :method_with_default_argument with unexpected arguments\n expected: ({})\n got: (nil)")
|
186
156
|
end
|
157
|
+
end
|
187
158
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
end
|
195
|
-
|
196
|
-
it "passes proc to expectation block with an argument" do
|
197
|
-
eval("@double.should_receive(:foo) {|arg, &block| expect(block.call).to eq(:bar)}")
|
198
|
-
@double.foo(:arg) { :bar }
|
199
|
-
end
|
200
|
-
|
201
|
-
it "passes proc to stub block without an argurment" do
|
202
|
-
eval("Spy.on(@double, :foo) {|&block| expect(block.call).to eq(:bar)}")
|
203
|
-
@double.foo { :bar }
|
204
|
-
end
|
159
|
+
it "fails if unexpected method called" do
|
160
|
+
expect {
|
161
|
+
@double.something("a","b","c")
|
162
|
+
violated
|
163
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received unexpected message :something with (\"a\", \"b\", \"c\")")
|
164
|
+
end
|
205
165
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
166
|
+
it "uses block for expectation if provided" do
|
167
|
+
@double.should_receive(:something) do | a, b |
|
168
|
+
expect(a).to eq "a"
|
169
|
+
expect(b).to eq "b"
|
170
|
+
"booh"
|
210
171
|
end
|
172
|
+
expect(@double.something("a", "b")).to eq "booh"
|
173
|
+
@double.rspec_verify
|
174
|
+
end
|
211
175
|
|
212
|
-
|
213
|
-
|
214
|
-
expect
|
215
|
-
to raise_error(RSpec::Mocks::MockExpectationError,
|
216
|
-
%Q|(Double "test double").not_expected(no args)\n expected: 0 times\n received: 1 time|
|
217
|
-
)
|
176
|
+
it "fails if expectation block fails" do
|
177
|
+
@double.should_receive(:something) do |bool|
|
178
|
+
expect(bool).to be_true
|
218
179
|
end
|
219
180
|
|
220
|
-
|
221
|
-
@double.
|
222
|
-
|
223
|
-
|
181
|
+
expect {
|
182
|
+
@double.something false
|
183
|
+
}.to raise_error(RSpec::Expectations::ExpectationNotMetError)
|
184
|
+
end
|
224
185
|
|
225
|
-
|
226
|
-
|
227
|
-
|
186
|
+
context "with Ruby > 1.8.6", :unless => RUBY_VERSION.to_s == '1.8.6' do
|
187
|
+
it "passes proc to expectation block without an argument" do
|
188
|
+
# We eval this because Ruby 1.8.6's syntax parser barfs on { |&block| ... }
|
189
|
+
# and prevents the entire spec suite from running.
|
190
|
+
eval("@double.should_receive(:foo) {|&block| expect(block.call).to eq(:bar)}")
|
191
|
+
@double.foo { :bar }
|
228
192
|
end
|
229
193
|
|
230
|
-
it "
|
231
|
-
@double.should_receive(:
|
232
|
-
|
194
|
+
it "passes proc to expectation block with an argument" do
|
195
|
+
eval("@double.should_receive(:foo) {|arg, &block| expect(block.call).to eq(:bar)}")
|
196
|
+
@double.foo(:arg) { :bar }
|
233
197
|
end
|
234
198
|
|
235
|
-
it "
|
236
|
-
@double.
|
237
|
-
|
199
|
+
it "passes proc to stub block without an argurment" do
|
200
|
+
eval("Spy.on(@double, :foo) {|&block| expect(block.call).to eq(:bar)}")
|
201
|
+
@double.foo { :bar }
|
238
202
|
end
|
239
203
|
|
240
|
-
it "
|
241
|
-
@double
|
242
|
-
|
204
|
+
it "passes proc to stub block with an argument" do
|
205
|
+
eval("Spy.on(@double, :foo) {|arg, &block| expect(block.call).to eq(:bar)}")
|
206
|
+
@double.foo(:arg) { :bar }
|
243
207
|
end
|
208
|
+
end
|
244
209
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
210
|
+
it "fails right away when method defined as never is received" do
|
211
|
+
@double.should_receive(:not_expected).never
|
212
|
+
expect { @double.not_expected }.
|
213
|
+
to raise_error(RSpec::Mocks::MockExpectationError,
|
214
|
+
%Q|(Double "test double").not_expected(no args)\n expected: 0 times\n received: 1 time|
|
215
|
+
)
|
216
|
+
end
|
252
217
|
|
253
|
-
|
254
|
-
|
218
|
+
it "raises RuntimeError by default" do
|
219
|
+
@double.should_receive(:something).and_raise
|
220
|
+
expect { @double.something }.to raise_error(RuntimeError)
|
221
|
+
end
|
255
222
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
expect(e.amount).to eq 2
|
261
|
-
expect(e.units).to eq :oz
|
262
|
-
end
|
263
|
-
end
|
223
|
+
it "raises RuntimeError with a message by default" do
|
224
|
+
@double.should_receive(:something).and_raise("error message")
|
225
|
+
expect { @double.something }.to raise_error(RuntimeError, "error message")
|
226
|
+
end
|
264
227
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
}.to raise_error(RSpec::Mocks::MockExpectationError)
|
270
|
-
end
|
228
|
+
it "raises an exception of a given type without an error message" do
|
229
|
+
@double.should_receive(:something).and_raise(StandardError)
|
230
|
+
expect { @double.something }.to raise_error(StandardError)
|
231
|
+
end
|
271
232
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
}.to throw_symbol(:blech)
|
277
|
-
end
|
233
|
+
it "raises an exception of a given type with a message" do
|
234
|
+
@double.should_receive(:something).and_raise(RuntimeError, "error message")
|
235
|
+
expect { @double.something }.to raise_error(RuntimeError, "error message")
|
236
|
+
end
|
278
237
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
@double.something "a", 2
|
284
|
-
@double.something [], {}, "joe", 7
|
285
|
-
@double.rspec_verify
|
286
|
-
end
|
238
|
+
it "raises a given instance of an exception" do
|
239
|
+
@double.should_receive(:something).and_raise(RuntimeError.new("error message"))
|
240
|
+
expect { @double.something }.to raise_error(RuntimeError, "error message")
|
241
|
+
end
|
287
242
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
243
|
+
class OutOfGas < StandardError
|
244
|
+
attr_reader :amount, :units
|
245
|
+
def initialize(amount, units)
|
246
|
+
@amount = amount
|
247
|
+
@units = units
|
293
248
|
end
|
249
|
+
end
|
294
250
|
|
295
|
-
|
296
|
-
|
297
|
-
expect {
|
298
|
-
@double.something
|
299
|
-
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (1)\n got: (no args)")
|
300
|
-
end
|
251
|
+
it "raises a given instance of an exception with arguments other than the standard 'message'" do
|
252
|
+
@double.should_receive(:something).and_raise(OutOfGas.new(2, :oz))
|
301
253
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
254
|
+
begin
|
255
|
+
@double.something
|
256
|
+
fail "OutOfGas was not raised"
|
257
|
+
rescue OutOfGas => e
|
258
|
+
expect(e.amount).to eq 2
|
259
|
+
expect(e.units).to eq :oz
|
307
260
|
end
|
261
|
+
end
|
308
262
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
@double.
|
313
|
-
|
314
|
-
|
315
|
-
end
|
263
|
+
it "does not raise when told to if args dont match" do
|
264
|
+
@double.should_receive(:something).with(2).and_raise(RuntimeError)
|
265
|
+
expect {
|
266
|
+
@double.something 1
|
267
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError)
|
268
|
+
end
|
316
269
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
@double.rspec_verify
|
324
|
-
end
|
270
|
+
it "throws when told to" do
|
271
|
+
@double.should_receive(:something).and_throw(:blech)
|
272
|
+
expect {
|
273
|
+
@double.something
|
274
|
+
}.to throw_symbol(:blech)
|
275
|
+
end
|
325
276
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
277
|
+
it "ignores args on any args" do
|
278
|
+
@double.should_receive(:something).at_least(:once).with(any_args)
|
279
|
+
@double.something
|
280
|
+
@double.something 1
|
281
|
+
@double.something "a", 2
|
282
|
+
@double.something [], {}, "joe", 7
|
283
|
+
@double.rspec_verify
|
284
|
+
end
|
333
285
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
expect(b).to eq [[99], [43], ["something fruity"]]
|
341
|
-
@double.rspec_verify
|
342
|
-
end
|
286
|
+
it "fails on no args if any args received" do
|
287
|
+
@double.should_receive(:something).with(no_args())
|
288
|
+
expect {
|
289
|
+
@double.something 1
|
290
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (no args)\n got: (1)")
|
291
|
+
end
|
343
292
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
@double.
|
348
|
-
|
349
|
-
|
350
|
-
end
|
293
|
+
it "fails when args are expected but none are received" do
|
294
|
+
@double.should_receive(:something).with(1)
|
295
|
+
expect {
|
296
|
+
@double.something
|
297
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" received :something with unexpected arguments\n expected: (1)\n got: (no args)")
|
298
|
+
end
|
351
299
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
expect(b).to eq [[99, :green, "go"], ["wait", :amber], ["stop", 12, :red]]
|
359
|
-
@double.rspec_verify
|
360
|
-
end
|
300
|
+
it "returns value from block by default" do
|
301
|
+
Spy.on(@double, :method_that_yields).and_yield
|
302
|
+
value = @double.method_that_yields { :returned_obj }
|
303
|
+
expect(value).to eq :returned_obj
|
304
|
+
@double.rspec_verify
|
305
|
+
end
|
361
306
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
307
|
+
it "yields 0 args to blocks that take a variable number of arguments" do
|
308
|
+
@double.should_receive(:yield_back).with(no_args()).once.and_yield
|
309
|
+
a = nil
|
310
|
+
@double.yield_back {|*x| a = x}
|
311
|
+
expect(a).to eq []
|
312
|
+
@double.rspec_verify
|
313
|
+
end
|
369
314
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
end
|
315
|
+
it "yields 0 args multiple times to blocks that take a variable number of arguments" do
|
316
|
+
@double.should_receive(:yield_back).once.with(no_args()).once.and_yield.
|
317
|
+
and_yield
|
318
|
+
b = []
|
319
|
+
@double.yield_back {|*a| b << a}
|
320
|
+
expect(b).to eq [ [], [] ]
|
321
|
+
@double.rspec_verify
|
322
|
+
end
|
379
323
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
end
|
324
|
+
it "yields one arg to blocks that take a variable number of arguments" do
|
325
|
+
@double.should_receive(:yield_back).with(no_args()).once.and_yield(99)
|
326
|
+
a = nil
|
327
|
+
@double.yield_back {|*x| a = x}
|
328
|
+
expect(a).to eq [99]
|
329
|
+
@double.rspec_verify
|
330
|
+
end
|
388
331
|
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
332
|
+
it "yields one arg 3 times consecutively to blocks that take a variable number of arguments" do
|
333
|
+
@double.should_receive(:yield_back).once.with(no_args()).once.and_yield(99).
|
334
|
+
and_yield(43).
|
335
|
+
and_yield("something fruity")
|
336
|
+
b = []
|
337
|
+
@double.yield_back {|*a| b << a}
|
338
|
+
expect(b).to eq [[99], [43], ["something fruity"]]
|
339
|
+
@double.rspec_verify
|
340
|
+
end
|
398
341
|
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
342
|
+
it "yields many args to blocks that take a variable number of arguments" do
|
343
|
+
@double.should_receive(:yield_back).with(no_args()).once.and_yield(99, 27, "go")
|
344
|
+
a = nil
|
345
|
+
@double.yield_back {|*x| a = x}
|
346
|
+
expect(a).to eq [99, 27, "go"]
|
347
|
+
@double.rspec_verify
|
348
|
+
end
|
405
349
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
350
|
+
it "yields many args 3 times consecutively to blocks that take a variable number of arguments" do
|
351
|
+
@double.should_receive(:yield_back).once.with(no_args()).once.and_yield(99, :green, "go").
|
352
|
+
and_yield("wait", :amber).
|
353
|
+
and_yield("stop", 12, :red)
|
354
|
+
b = []
|
355
|
+
@double.yield_back {|*a| b << a}
|
356
|
+
expect(b).to eq [[99, :green, "go"], ["wait", :amber], ["stop", 12, :red]]
|
357
|
+
@double.rspec_verify
|
358
|
+
end
|
415
359
|
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
360
|
+
it "yields single value" do
|
361
|
+
@double.should_receive(:yield_back).with(no_args()).once.and_yield(99)
|
362
|
+
a = nil
|
363
|
+
@double.yield_back {|x| a = x}
|
364
|
+
expect(a).to eq 99
|
365
|
+
@double.rspec_verify
|
366
|
+
end
|
422
367
|
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
368
|
+
it "yields single value 3 times consecutively" do
|
369
|
+
@double.should_receive(:yield_back).once.with(no_args()).once.and_yield(99).
|
370
|
+
and_yield(43).
|
371
|
+
and_yield("something fruity")
|
372
|
+
b = []
|
373
|
+
@double.yield_back {|a| b << a}
|
374
|
+
expect(b).to eq [99, 43, "something fruity"]
|
375
|
+
@double.rspec_verify
|
376
|
+
end
|
428
377
|
|
429
|
-
|
430
|
-
|
378
|
+
it "yields two values" do
|
379
|
+
@double.should_receive(:yield_back).with(no_args()).once.and_yield('wha', 'zup')
|
380
|
+
a, b = nil
|
381
|
+
@double.yield_back {|x,y| a=x; b=y}
|
382
|
+
expect(a).to eq 'wha'
|
383
|
+
expect(b).to eq 'zup'
|
384
|
+
@double.rspec_verify
|
385
|
+
end
|
431
386
|
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
387
|
+
it "yields two values 3 times consecutively" do
|
388
|
+
@double.should_receive(:yield_back).once.with(no_args()).once.and_yield('wha', 'zup').
|
389
|
+
and_yield('not', 'down').
|
390
|
+
and_yield(14, 65)
|
391
|
+
c = []
|
392
|
+
@double.yield_back {|a,b| c << [a, b]}
|
393
|
+
expect(c).to eq [['wha', 'zup'], ['not', 'down'], [14, 65]]
|
394
|
+
@double.rspec_verify
|
395
|
+
end
|
437
396
|
|
438
|
-
|
439
|
-
|
397
|
+
it "fails when calling yielding method with wrong arity" do
|
398
|
+
@double.should_receive(:yield_back).with(no_args()).once.and_yield('wha', 'zup')
|
399
|
+
expect {
|
400
|
+
@double.yield_back {|a|}
|
401
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" yielded |\"wha\", \"zup\"| to block with arity of 1")
|
402
|
+
end
|
440
403
|
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
404
|
+
it "fails when calling yielding method consecutively with wrong arity" do
|
405
|
+
@double.should_receive(:yield_back).once.with(no_args()).once.and_yield('wha', 'zup').
|
406
|
+
and_yield('down').
|
407
|
+
and_yield(14, 65)
|
408
|
+
expect {
|
409
|
+
c = []
|
410
|
+
@double.yield_back {|a,b| c << [a, b]}
|
411
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" yielded |\"down\"| to block with arity of 2")
|
412
|
+
end
|
449
413
|
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
double.
|
454
|
-
|
455
|
-
|
414
|
+
it "fails when calling yielding method without block" do
|
415
|
+
@double.should_receive(:yield_back).with(no_args()).once.and_yield('wha', 'zup')
|
416
|
+
expect {
|
417
|
+
@double.yield_back
|
418
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError, "Double \"test double\" asked to yield |[\"wha\", \"zup\"]| but no block was passed")
|
419
|
+
end
|
456
420
|
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
# * raises a NameError when called indirectly
|
463
|
-
#
|
464
|
-
# Once Object#method_missing has been called at least once (on any object)
|
465
|
-
# it starts behaving differently:
|
466
|
-
# * raises a NameError when called directly
|
467
|
-
# * raises a NameError when called indirectly
|
468
|
-
#
|
469
|
-
# There was a bug in Mock#method_missing that relied on the fact
|
470
|
-
# that calling Object#method_missing directly raises a NoMethodError.
|
471
|
-
# This example tests that the bug doesn't exist anymore.
|
421
|
+
it "is able to double send" do
|
422
|
+
@double.should_receive(:send).with(any_args)
|
423
|
+
@double.send 'hi'
|
424
|
+
@double.rspec_verify
|
425
|
+
end
|
472
426
|
|
427
|
+
it "is able to raise from method calling yielding double" do
|
428
|
+
@double.should_receive(:yield_me).and_yield 44
|
473
429
|
|
474
|
-
|
475
|
-
|
430
|
+
expect {
|
431
|
+
@double.yield_me do |x|
|
432
|
+
raise "Bang"
|
433
|
+
end
|
434
|
+
}.to raise_error(StandardError, "Bang")
|
476
435
|
|
436
|
+
@double.rspec_verify
|
437
|
+
end
|
477
438
|
|
478
|
-
|
439
|
+
it "clears expectations after verify" do
|
440
|
+
@double.should_receive(:foobar)
|
441
|
+
@double.foobar
|
442
|
+
@double.rspec_verify
|
443
|
+
expect {
|
479
444
|
@double.foobar
|
480
|
-
|
445
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError, %q|Double "test double" received unexpected message :foobar with (no args)|)
|
446
|
+
end
|
481
447
|
|
482
|
-
|
483
|
-
|
484
|
-
|
448
|
+
it "restores objects to their original state on rspec_reset" do
|
449
|
+
double = double("this is a double")
|
450
|
+
double.should_receive(:blah)
|
451
|
+
double.rspec_reset
|
452
|
+
double.rspec_verify #should throw if reset didn't work
|
453
|
+
end
|
485
454
|
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
455
|
+
it "works even after method_missing starts raising NameErrors instead of NoMethodErrors" do
|
456
|
+
# Object#method_missing throws either NameErrors or NoMethodErrors.
|
457
|
+
#
|
458
|
+
# On a fresh ruby program Object#method_missing:
|
459
|
+
# * raises a NoMethodError when called directly
|
460
|
+
# * raises a NameError when called indirectly
|
461
|
+
#
|
462
|
+
# Once Object#method_missing has been called at least once (on any object)
|
463
|
+
# it starts behaving differently:
|
464
|
+
# * raises a NameError when called directly
|
465
|
+
# * raises a NameError when called indirectly
|
466
|
+
#
|
467
|
+
# There was a bug in Mock#method_missing that relied on the fact
|
468
|
+
# that calling Object#method_missing directly raises a NoMethodError.
|
469
|
+
# This example tests that the bug doesn't exist anymore.
|
470
|
+
|
471
|
+
|
472
|
+
# Ensures that method_missing always raises NameErrors.
|
473
|
+
a_method_that_doesnt_exist rescue
|
474
|
+
|
475
|
+
|
476
|
+
@double.should_receive(:foobar)
|
477
|
+
@double.foobar
|
478
|
+
@double.rspec_verify
|
479
|
+
|
480
|
+
expect { @double.foobar }.to_not raise_error(NameError)
|
481
|
+
expect { @double.foobar }.to raise_error(RSpec::Mocks::MockExpectationError)
|
482
|
+
end
|
494
483
|
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
484
|
+
it "temporarily replaces a method stub on a double" do
|
485
|
+
Spy.on(@double, :msg).and_return(:stub_value)
|
486
|
+
@double.should_receive(:msg).with(:arg).and_return(:double_value)
|
487
|
+
expect(@double.msg(:arg)).to equal(:double_value)
|
488
|
+
expect(@double.msg).to equal(:stub_value)
|
489
|
+
expect(@double.msg).to equal(:stub_value)
|
490
|
+
@double.rspec_verify
|
491
|
+
end
|
503
492
|
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
493
|
+
it "does not require a different signature to replace a method stub" do
|
494
|
+
Spy.on(@double, :msg).and_return(:stub_value)
|
495
|
+
@double.should_receive(:msg).and_return(:double_value)
|
496
|
+
expect(@double.msg(:arg)).to equal(:double_value)
|
497
|
+
expect(@double.msg).to equal(:stub_value)
|
498
|
+
expect(@double.msg).to equal(:stub_value)
|
499
|
+
@double.rspec_verify
|
500
|
+
end
|
509
501
|
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
expect(non_double.msg).to equal(:stub_value)
|
516
|
-
expect(non_double.msg).to equal(:stub_value)
|
517
|
-
non_double.rspec_verify
|
518
|
-
end
|
502
|
+
it "raises an error when a previously stubbed method has a negative expectation" do
|
503
|
+
Spy.on(@double, :msg).and_return(:stub_value)
|
504
|
+
@double.should_not_receive(:msg)
|
505
|
+
expect { @double.msg(:arg) }.to raise_error(RSpec::Mocks::MockExpectationError)
|
506
|
+
end
|
519
507
|
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
508
|
+
it "temporarily replaces a method stub on a non-double" do
|
509
|
+
non_double = Object.new
|
510
|
+
Spy.on(non_double, :msg).and_return(:stub_value)
|
511
|
+
non_double.should_receive(:msg).with(:arg).and_return(:double_value)
|
512
|
+
expect(non_double.msg(:arg)).to equal(:double_value)
|
513
|
+
expect(non_double.msg).to equal(:stub_value)
|
514
|
+
expect(non_double.msg).to equal(:stub_value)
|
515
|
+
non_double.rspec_verify
|
516
|
+
end
|
526
517
|
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
518
|
+
it "returns the stubbed value when no new value specified" do
|
519
|
+
Spy.on(@double, :msg).and_return(:stub_value)
|
520
|
+
@double.should_receive(:msg)
|
521
|
+
expect(@double.msg).to equal(:stub_value)
|
522
|
+
@double.rspec_verify
|
523
|
+
end
|
533
524
|
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
end
|
525
|
+
it "returns the stubbed value when stubbed with args and no new value specified" do
|
526
|
+
Spy.on(@double, :msg).with(:arg).and_return(:stub_value)
|
527
|
+
@double.should_receive(:msg).with(:arg)
|
528
|
+
expect(@double.msg(:arg)).to equal(:stub_value)
|
529
|
+
@double.rspec_verify
|
530
|
+
end
|
541
531
|
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
File.rspec_verify
|
550
|
-
end
|
532
|
+
it "does not mess with the stub's yielded values when also doubleed" do
|
533
|
+
Spy.on(@double, :yield_back).and_yield(:stub_value)
|
534
|
+
@double.should_receive(:yield_back).and_yield(:double_value)
|
535
|
+
@double.yield_back{|v| expect(v).to eq :double_value }
|
536
|
+
@double.yield_back{|v| expect(v).to eq :stub_value }
|
537
|
+
@double.rspec_verify
|
538
|
+
end
|
551
539
|
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
540
|
+
it "yields multiple values after a similar stub" do
|
541
|
+
FSpy.on(ile, :open).and_yield(:stub_value)
|
542
|
+
File.should_receive(:open).and_yield(:first_call).and_yield(:second_call)
|
543
|
+
yielded_args = []
|
544
|
+
File.open {|v| yielded_args << v }
|
545
|
+
expect(yielded_args).to eq [:first_call, :second_call]
|
546
|
+
File.open {|v| expect(v).to eq :stub_value }
|
547
|
+
File.rspec_verify
|
548
|
+
end
|
556
549
|
|
550
|
+
it "assigns stub return values" do
|
551
|
+
double = Spy.double('name', :message => :response)
|
552
|
+
expect(double.message).to eq :response
|
557
553
|
end
|
558
554
|
|
559
|
-
|
560
|
-
before(:each) do
|
561
|
-
@double = double("double")
|
562
|
-
@calls = 0
|
563
|
-
end
|
555
|
+
end
|
564
556
|
|
565
|
-
|
566
|
-
|
567
|
-
|
557
|
+
describe "a double message receiving a block" do
|
558
|
+
before(:each) do
|
559
|
+
@double = Spy.double("double")
|
560
|
+
@calls = 0
|
561
|
+
end
|
568
562
|
|
569
|
-
|
570
|
-
|
563
|
+
def add_call
|
564
|
+
@calls = @calls + 1
|
565
|
+
end
|
571
566
|
|
572
|
-
|
567
|
+
it "calls the block after #should_receive" do
|
568
|
+
@double.should_receive(:foo) { add_call }
|
573
569
|
|
574
|
-
|
575
|
-
end
|
570
|
+
@double.foo
|
576
571
|
|
577
|
-
|
578
|
-
|
579
|
-
@double.should_receive(:foo) { add_call }
|
572
|
+
expect(@calls).to eq 1
|
573
|
+
end
|
580
574
|
|
581
|
-
|
575
|
+
it "calls the block after #should_receive after a similar stub" do
|
576
|
+
Spy.on(@double, :foo).and_return(:bar)
|
577
|
+
@double.should_receive(:foo) { add_call }
|
582
578
|
|
583
|
-
|
584
|
-
end
|
579
|
+
@double.foo
|
585
580
|
|
586
|
-
|
587
|
-
|
581
|
+
expect(@calls).to eq 1
|
582
|
+
end
|
588
583
|
|
589
|
-
|
584
|
+
it "calls the block after #once" do
|
585
|
+
@double.should_receive(:foo).once { add_call }
|
590
586
|
|
591
|
-
|
592
|
-
end
|
587
|
+
@double.foo
|
593
588
|
|
594
|
-
|
595
|
-
|
589
|
+
expect(@calls).to eq 1
|
590
|
+
end
|
596
591
|
|
597
|
-
|
598
|
-
|
592
|
+
it "calls the block after #twice" do
|
593
|
+
@double.should_receive(:foo).twice { add_call }
|
599
594
|
|
600
|
-
|
601
|
-
|
595
|
+
@double.foo
|
596
|
+
@double.foo
|
602
597
|
|
603
|
-
|
604
|
-
|
598
|
+
expect(@calls).to eq 2
|
599
|
+
end
|
605
600
|
|
606
|
-
|
601
|
+
it "calls the block after #times" do
|
602
|
+
@double.should_receive(:foo).exactly(10).times { add_call }
|
607
603
|
|
608
|
-
|
609
|
-
|
604
|
+
(1..10).each { @double.foo }
|
605
|
+
|
606
|
+
expect(@calls).to eq 10
|
607
|
+
end
|
610
608
|
|
611
|
-
|
612
|
-
|
609
|
+
it "calls the block after #any_number_of_times" do
|
610
|
+
@double.should_receive(:foo).any_number_of_times { add_call }
|
613
611
|
|
614
|
-
|
612
|
+
(1..7).each { @double.foo }
|
615
613
|
|
616
|
-
|
617
|
-
|
614
|
+
expect(@calls).to eq 7
|
615
|
+
end
|
618
616
|
|
619
|
-
|
620
|
-
|
621
|
-
|
617
|
+
it "calls the block after #ordered" do
|
618
|
+
@double.should_receive(:foo).ordered { add_call }
|
619
|
+
@double.should_receive(:bar).ordered { add_call }
|
622
620
|
|
623
|
-
|
624
|
-
|
621
|
+
@double.foo
|
622
|
+
@double.bar
|
625
623
|
|
626
|
-
|
627
|
-
end
|
624
|
+
expect(@calls).to eq 2
|
628
625
|
end
|
626
|
+
end
|
629
627
|
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
end
|
628
|
+
describe 'string representation generated by #to_s' do
|
629
|
+
it 'does not contain < because that might lead to invalid HTML in some situations' do
|
630
|
+
double = Spy.double("Dog")
|
631
|
+
valid_html_str = "#{double}"
|
632
|
+
expect(valid_html_str).not_to include('<')
|
636
633
|
end
|
634
|
+
end
|
637
635
|
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
end
|
636
|
+
describe "string representation generated by #to_str" do
|
637
|
+
it "looks the same as #to_s" do
|
638
|
+
double = Spy.double("Foo")
|
639
|
+
expect(double.to_str).to eq double.to_s
|
643
640
|
end
|
641
|
+
end
|
644
642
|
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
643
|
+
describe "double created with no name" do
|
644
|
+
it "does not use a name in a failure message" do
|
645
|
+
double = Spy.double()
|
646
|
+
expect {double.foo}.to raise_error(/Double received/)
|
647
|
+
end
|
650
648
|
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
end
|
649
|
+
it "does respond to initially stubbed methods" do
|
650
|
+
double = Spy.double(:foo => "woo", :bar => "car")
|
651
|
+
expect(double.foo).to eq "woo"
|
652
|
+
expect(double.bar).to eq "car"
|
656
653
|
end
|
654
|
+
end
|
657
655
|
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
656
|
+
describe "==" do
|
657
|
+
it "sends '== self' to the comparison object" do
|
658
|
+
first = Spy.double('first')
|
659
|
+
second = Spy.double('second')
|
662
660
|
|
663
|
-
|
664
|
-
|
665
|
-
end
|
661
|
+
first.should_receive(:==).with(second)
|
662
|
+
second == first
|
666
663
|
end
|
664
|
+
end
|
667
665
|
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
end
|
666
|
+
describe "with" do
|
667
|
+
before { @double = Spy.double('double') }
|
668
|
+
context "with args" do
|
669
|
+
context "with matching args" do
|
670
|
+
it "passes" do
|
671
|
+
@double.should_receive(:foo).with('bar')
|
672
|
+
@double.foo('bar')
|
676
673
|
end
|
674
|
+
end
|
677
675
|
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
end
|
676
|
+
context "with non-matching args" do
|
677
|
+
it "fails" do
|
678
|
+
@double.should_receive(:foo).with('bar')
|
679
|
+
expect do
|
680
|
+
@double.foo('baz')
|
681
|
+
end.to raise_error
|
682
|
+
@double.rspec_reset
|
686
683
|
end
|
684
|
+
end
|
687
685
|
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
end
|
686
|
+
context "with non-matching doubles" do
|
687
|
+
it "fails" do
|
688
|
+
d1 = Spy.double('1')
|
689
|
+
d2 = Spy.double('2')
|
690
|
+
@double.should_receive(:foo).with(d1)
|
691
|
+
expect do
|
692
|
+
@double.foo(d2)
|
693
|
+
end.to raise_error
|
694
|
+
@double.rspec_reset
|
698
695
|
end
|
696
|
+
end
|
699
697
|
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
end
|
698
|
+
context "with non-matching doubles as_null_object" do
|
699
|
+
it "fails" do
|
700
|
+
d1 = Spy.double('1').as_null_object
|
701
|
+
d2 = Spy.double('2').as_null_object
|
702
|
+
@double.should_receive(:foo).with(d1)
|
703
|
+
expect do
|
704
|
+
@double.foo(d2)
|
705
|
+
end.to raise_error
|
706
|
+
@double.rspec_reset
|
710
707
|
end
|
711
708
|
end
|
709
|
+
end
|
712
710
|
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
end
|
711
|
+
context "with a block" do
|
712
|
+
context "with matching args" do
|
713
|
+
it "returns the result of the block" do
|
714
|
+
@double.should_receive(:foo).with('bar') { 'baz' }
|
715
|
+
expect(@double.foo('bar')).to eq('baz')
|
719
716
|
end
|
717
|
+
end
|
720
718
|
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
end
|
719
|
+
context "with non-matching args" do
|
720
|
+
it "fails" do
|
721
|
+
@double.should_receive(:foo).with('bar') { 'baz' }
|
722
|
+
expect do
|
723
|
+
expect(@double.foo('wrong')).to eq('baz')
|
724
|
+
end.to raise_error(/received :foo with unexpected arguments/)
|
725
|
+
@double.rspec_reset
|
729
726
|
end
|
730
727
|
end
|
731
728
|
end
|
732
|
-
|
733
729
|
end
|
734
730
|
end
|