spy 0.0.1
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/.gitignore +18 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +133 -0
- data/Rakefile +8 -0
- data/TODO.md +8 -0
- data/lib/spy.rb +259 -0
- data/lib/spy/double.rb +11 -0
- data/lib/spy/dsl.rb +7 -0
- data/lib/spy/version.rb +3 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/spy/and_call_original_spec.rb +152 -0
- data/spec/spy/and_yield_spec.rb +114 -0
- data/spec/spy/bug_report_10260_spec.rb +8 -0
- data/spec/spy/bug_report_10263_spec.rb +24 -0
- data/spec/spy/bug_report_496_spec.rb +18 -0
- data/spec/spy/bug_report_600_spec.rb +24 -0
- data/spec/spy/bug_report_7611_spec.rb +16 -0
- data/spec/spy/bug_report_8165_spec.rb +31 -0
- data/spec/spy/bug_report_830_spec.rb +21 -0
- data/spec/spy/bug_report_957_spec.rb +22 -0
- data/spec/spy/double_spec.rb +12 -0
- data/spec/spy/failing_argument_matchers_spec.rb +94 -0
- data/spec/spy/hash_excluding_matcher_spec.rb +67 -0
- data/spec/spy/hash_including_matcher_spec.rb +90 -0
- data/spec/spy/mock_spec.rb +734 -0
- data/spec/spy/multiple_return_value_spec.rb +119 -0
- data/spec/spy/mutate_const_spec.rb +481 -0
- data/spec/spy/nil_expectation_warning_spec.rb +56 -0
- data/spec/spy/null_object_mock_spec.rb +107 -0
- data/spec/spy/options_hash_spec.rb +35 -0
- data/spec/spy/partial_mock_spec.rb +196 -0
- data/spec/spy/passing_argument_matchers_spec.rb +142 -0
- data/spec/spy/precise_counts_spec.rb +68 -0
- data/spec/spy/serialization_spec.rb +110 -0
- data/spec/spy/stash_spec.rb +54 -0
- data/spec/spy/stub_implementation_spec.rb +62 -0
- data/spec/spy/stub_spec.rb +85 -0
- data/spec/spy/stubbed_message_expectations_spec.rb +47 -0
- data/spec/spy/test_double_spec.rb +57 -0
- data/spec/spy/to_ary_spec.rb +40 -0
- data/spy.gemspec +21 -0
- data/test/spy/test_double.rb +19 -0
- data/test/test_helper.rb +6 -0
- data/test/test_spy.rb +258 -0
- metadata +157 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Mocks
|
5
|
+
describe "PreciseCounts" do
|
6
|
+
before(:each) do
|
7
|
+
@double = double("test double")
|
8
|
+
end
|
9
|
+
|
10
|
+
it "fails when exactly n times method is called less than n times" do
|
11
|
+
@double.should_receive(:do_something).exactly(3).times
|
12
|
+
@double.do_something
|
13
|
+
@double.do_something
|
14
|
+
expect {
|
15
|
+
@double.rspec_verify
|
16
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "fails fast when exactly n times method is called more than n times" do
|
20
|
+
@double.should_receive(:do_something).exactly(3).times
|
21
|
+
@double.do_something
|
22
|
+
@double.do_something
|
23
|
+
@double.do_something
|
24
|
+
expect {
|
25
|
+
@double.do_something
|
26
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "fails when exactly n times method is never called" do
|
30
|
+
@double.should_receive(:do_something).exactly(3).times
|
31
|
+
expect {
|
32
|
+
@double.rspec_verify
|
33
|
+
}.to raise_error(RSpec::Mocks::MockExpectationError)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "passes if exactly n times method is called exactly n times" do
|
37
|
+
@double.should_receive(:do_something).exactly(3).times
|
38
|
+
@double.do_something
|
39
|
+
@double.do_something
|
40
|
+
@double.do_something
|
41
|
+
@double.rspec_verify
|
42
|
+
end
|
43
|
+
|
44
|
+
it "returns the value given by a block when the exactly once method is called" do
|
45
|
+
@double.should_receive(:to_s).exactly(:once) { "testing" }
|
46
|
+
expect(@double.to_s).to eq "testing"
|
47
|
+
@double.rspec_verify
|
48
|
+
end
|
49
|
+
|
50
|
+
it "passes mutiple calls with different args" do
|
51
|
+
@double.should_receive(:do_something).once.with(1)
|
52
|
+
@double.should_receive(:do_something).once.with(2)
|
53
|
+
@double.do_something(1)
|
54
|
+
@double.do_something(2)
|
55
|
+
@double.rspec_verify
|
56
|
+
end
|
57
|
+
|
58
|
+
it "passes multiple calls with different args and counts" do
|
59
|
+
@double.should_receive(:do_something).twice.with(1)
|
60
|
+
@double.should_receive(:do_something).once.with(2)
|
61
|
+
@double.do_something(1)
|
62
|
+
@double.do_something(2)
|
63
|
+
@double.do_something(1)
|
64
|
+
@double.rspec_verify
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Mocks
|
5
|
+
describe Serialization do
|
6
|
+
|
7
|
+
class SerializableObject < Struct.new(:foo, :bar); end
|
8
|
+
|
9
|
+
class SerializableMockProxy
|
10
|
+
attr_reader :mock_proxy
|
11
|
+
|
12
|
+
def initialize(mock_proxy)
|
13
|
+
@mock_proxy = mock_proxy
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
other.class == self.class && other.mock_proxy == mock_proxy
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.with_yaml_loaded(&block)
|
22
|
+
context 'with YAML loaded' do
|
23
|
+
module_eval(&block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.without_yaml_loaded(&block)
|
28
|
+
context 'without YAML loaded' do
|
29
|
+
before do
|
30
|
+
# We can't really unload yaml, but we can fake it here...
|
31
|
+
hide_const("YAML")
|
32
|
+
Struct.class_eval do
|
33
|
+
alias __old_to_yaml to_yaml
|
34
|
+
undef to_yaml
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module_eval(&block)
|
39
|
+
|
40
|
+
after do
|
41
|
+
Struct.class_eval do
|
42
|
+
alias to_yaml __old_to_yaml
|
43
|
+
undef __old_to_yaml
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
let(:serializable_object) { RSpec::Mocks::SerializableObject.new(7, "something") }
|
50
|
+
|
51
|
+
def set_stub
|
52
|
+
Spy.on(serializable_object, :bazz => 5)
|
53
|
+
end
|
54
|
+
|
55
|
+
shared_examples_for 'normal YAML serialization' do
|
56
|
+
it 'serializes to yaml the same with and without stubbing, using #to_yaml' do
|
57
|
+
expect { set_stub }.to_not change { serializable_object.to_yaml }
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'serializes to yaml the same with and without stubbing, using YAML.dump' do
|
61
|
+
expect { set_stub }.to_not change { ::YAML.dump(serializable_object) }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
with_yaml_loaded do
|
66
|
+
compiled_with_psych = begin
|
67
|
+
require 'psych'
|
68
|
+
true
|
69
|
+
rescue LoadError
|
70
|
+
false
|
71
|
+
end
|
72
|
+
|
73
|
+
if compiled_with_psych
|
74
|
+
context 'using Syck as the YAML engine' do
|
75
|
+
before(:each) { ::YAML::ENGINE.yamler = 'syck' }
|
76
|
+
it_behaves_like 'normal YAML serialization'
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'using Psych as the YAML engine' do
|
80
|
+
before(:each) { ::YAML::ENGINE.yamler = 'psych' }
|
81
|
+
it_behaves_like 'normal YAML serialization'
|
82
|
+
end
|
83
|
+
else
|
84
|
+
it_behaves_like 'normal YAML serialization'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
without_yaml_loaded do
|
89
|
+
it 'does not add #to_yaml to the stubbed object' do
|
90
|
+
expect(serializable_object).not_to respond_to(:to_yaml)
|
91
|
+
set_stub
|
92
|
+
expect(serializable_object).not_to respond_to(:to_yaml)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'marshals the same with and without stubbing' do
|
97
|
+
expect { set_stub }.to_not change { Marshal.dump(serializable_object) }
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "an object that has its own mock_proxy instance variable" do
|
101
|
+
let(:serializable_object) { RSpec::Mocks::SerializableMockProxy.new(:my_mock_proxy) }
|
102
|
+
|
103
|
+
it 'does not interfere with its marshalling' do
|
104
|
+
marshalled_copy = Marshal.load(Marshal.dump(serializable_object))
|
105
|
+
expect(marshalled_copy).to eq serializable_object
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Mocks
|
5
|
+
|
6
|
+
describe "only stashing the original method" do
|
7
|
+
let(:klass) do
|
8
|
+
Class.new do
|
9
|
+
def self.foo(arg)
|
10
|
+
:original_value
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "keeps the original method intact after multiple expectations are added on the same method" do
|
16
|
+
klass.should_receive(:foo).with(:fizbaz).and_return(:wowwow)
|
17
|
+
klass.should_receive(:foo).with(:bazbar).and_return(:okay)
|
18
|
+
|
19
|
+
klass.foo(:fizbaz)
|
20
|
+
klass.foo(:bazbar)
|
21
|
+
klass.rspec_verify
|
22
|
+
|
23
|
+
klass.rspec_reset
|
24
|
+
expect(klass.foo(:yeah)).to equal(:original_value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "when a class method is aliased on a subclass and the method is mocked" do
|
29
|
+
let(:klass) do
|
30
|
+
Class.new do
|
31
|
+
class << self
|
32
|
+
alias alternate_new new
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it "restores the original aliased public method" do
|
38
|
+
klass = Class.new do
|
39
|
+
class << self
|
40
|
+
alias alternate_new new
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
klass.should_receive(:alternate_new)
|
45
|
+
expect(klass.alternate_new).to be_nil
|
46
|
+
|
47
|
+
klass.rspec_verify
|
48
|
+
|
49
|
+
klass.rspec_reset
|
50
|
+
expect(klass.alternate_new).to be_an_instance_of(klass)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Mocks
|
5
|
+
describe "stub implementation" do
|
6
|
+
describe "with no args" do
|
7
|
+
it "execs the block when called" do
|
8
|
+
obj = stub()
|
9
|
+
Spy.stub(obj, :foo).and_return { :bar }
|
10
|
+
expect(obj.foo).to eq :bar
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "with one arg" do
|
15
|
+
it "execs the block with that arg when called" do
|
16
|
+
obj = stub()
|
17
|
+
Spy.stub(obj, :foo).and_return {|given| given}
|
18
|
+
expect(obj.foo(:bar)).to eq :bar
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "with variable args" do
|
23
|
+
it "execs the block when called" do
|
24
|
+
obj = stub()
|
25
|
+
Spy.stub(obj, :foo).and_return {|*given| given.first}
|
26
|
+
expect(obj.foo(:bar)).to eq :bar
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
describe "unstub implementation" do
|
33
|
+
it "replaces the stubbed method with the original method" do
|
34
|
+
obj = Object.new
|
35
|
+
def obj.foo; :original; end
|
36
|
+
Spy.stub(obj, :foo)
|
37
|
+
Spy.off(obj, :foo)
|
38
|
+
expect(obj.foo).to eq :original
|
39
|
+
end
|
40
|
+
|
41
|
+
it "restores the correct implementations when stubbed and unstubbed on a parent and child class" do
|
42
|
+
parent = Class.new
|
43
|
+
child = Class.new(parent)
|
44
|
+
|
45
|
+
Spy.stub(parent, :new)
|
46
|
+
Spy.stub(child, :new)
|
47
|
+
Spy.off(parent, :new)
|
48
|
+
Spy.off(child, :new)
|
49
|
+
|
50
|
+
expect(parent.new).to be_an_instance_of parent
|
51
|
+
expect(child.new).to be_an_instance_of child
|
52
|
+
end
|
53
|
+
|
54
|
+
it "raises a MockExpectationError if the method has not been stubbed" do
|
55
|
+
obj = Object.new
|
56
|
+
expect {
|
57
|
+
Spy.off(obj, :foo)
|
58
|
+
}.to raise_error
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Mocks
|
5
|
+
describe "A method stub" do
|
6
|
+
before(:each) do
|
7
|
+
@class = Class.new do
|
8
|
+
class << self
|
9
|
+
def existing_class_method
|
10
|
+
existing_private_class_method
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
def existing_private_class_method
|
15
|
+
:original_value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def existing_instance_method
|
20
|
+
existing_private_instance_method
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def existing_private_instance_method
|
25
|
+
:original_value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
@instance = @class.new
|
29
|
+
@stub = Object.new
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "using Spy.stub" do
|
33
|
+
it "returns declared value when message is received" do
|
34
|
+
Spy.stub(@instance, :msg).and_return(:return_value)
|
35
|
+
expect(@instance.msg).to equal(:return_value)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "instructs an instance to respond_to the message" do
|
40
|
+
Spy.stub(@instance, :msg)
|
41
|
+
expect(@instance).to respond_to(:msg)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "instructs a class object to respond_to the message" do
|
45
|
+
Spy.stub(@class, :msg)
|
46
|
+
expect(@class).to respond_to(:msg)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "handles multiple stubbed methods" do
|
50
|
+
Spy.stub(@instance, :msg1 => 1, :msg2 => 2)
|
51
|
+
expect(@instance.msg1).to eq(1)
|
52
|
+
expect(@instance.msg2).to eq(2)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "yields a specified object" do
|
56
|
+
Spy.stub(@instance, :method_that_yields).and_yield(:yielded_obj)
|
57
|
+
current_value = :value_before
|
58
|
+
@instance.method_that_yields {|val| current_value = val}
|
59
|
+
expect(current_value).to eq :yielded_obj
|
60
|
+
end
|
61
|
+
|
62
|
+
it "yields a specified object and return another specified object" do
|
63
|
+
yielded_obj = double("my mock")
|
64
|
+
Spy.stub(yielded_obj, :foo)
|
65
|
+
Spy.stub(@instance, :method_that_yields_and_returns).and_yield(yielded_obj).and_return(:baz)
|
66
|
+
expect(@instance.method_that_yields_and_returns { |o| o.foo :bar }).to eq :baz
|
67
|
+
end
|
68
|
+
|
69
|
+
it "throws when told to" do
|
70
|
+
Spy.stub(@stub, :something).and_throw(:up)
|
71
|
+
expect { @stub.something }.to throw_symbol(:up)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "throws with argument when told to" do
|
75
|
+
Spy.stub(@stub, :something).and_throw(:up, 'high')
|
76
|
+
expect { @stub.something }.to throw_symbol(:up, 'high')
|
77
|
+
end
|
78
|
+
|
79
|
+
it "overrides a pre-existing method" do
|
80
|
+
Spy.stub(@stub, :existing_instance_method).and_return(:updated_stub_value)
|
81
|
+
expect(@stub.existing_instance_method).to eq :updated_stub_value
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "expection set on previously stubbed method" do
|
4
|
+
it "fails if message is not received after expectation is set" do
|
5
|
+
double = double(:msg => nil)
|
6
|
+
double.msg
|
7
|
+
double.should_receive(:msg)
|
8
|
+
expect { double.rspec_verify }.to raise_error(RSpec::Mocks::MockExpectationError)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "outputs arguments of similar calls" do
|
12
|
+
double = double('double', :foo => true)
|
13
|
+
double.should_receive(:foo).with('first')
|
14
|
+
double.foo('second')
|
15
|
+
double.foo('third')
|
16
|
+
expect {
|
17
|
+
double.rspec_verify
|
18
|
+
}.to raise_error(%Q|Double "double" received :foo with unexpected arguments\n expected: ("first")\n got: ("second"), ("third")|)
|
19
|
+
double.rspec_reset
|
20
|
+
end
|
21
|
+
|
22
|
+
context "with argument constraint on stub" do
|
23
|
+
it "matches any args if no arg constraint set on expectation" do
|
24
|
+
double = double("mock")
|
25
|
+
Spy.on(double, :foo).with(3).and_return("stub")
|
26
|
+
double.should_receive(:foo).at_least(:once).and_return("expectation")
|
27
|
+
double.foo
|
28
|
+
double.rspec_verify
|
29
|
+
end
|
30
|
+
|
31
|
+
it "matches specific args set on expectation" do
|
32
|
+
double = double("mock")
|
33
|
+
Spy.on(double, :foo).with(3).and_return("stub")
|
34
|
+
double.should_receive(:foo).at_least(:once).with(4).and_return("expectation")
|
35
|
+
double.foo(4)
|
36
|
+
double.rspec_verify
|
37
|
+
end
|
38
|
+
|
39
|
+
it "fails if expectation's arg constraint is not met" do
|
40
|
+
double = double("mock")
|
41
|
+
Spy.on(double, :foo).with(3).and_return("stub")
|
42
|
+
double.should_receive(:foo).at_least(:once).with(4).and_return("expectation")
|
43
|
+
double.foo(3)
|
44
|
+
expect { double.rspec_verify }.to raise_error(/expected: \(4\)\s+got: \(3\)/)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Mocks
|
5
|
+
describe TestDouble do
|
6
|
+
before(:all) do
|
7
|
+
Module.class_eval do
|
8
|
+
private
|
9
|
+
def use; end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:all) do
|
14
|
+
Module.class_eval do
|
15
|
+
undef use
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'can be extended onto a module to make it a pure test double that can mock private methods' do
|
20
|
+
double = Module.new
|
21
|
+
Spy.on(double, :use)
|
22
|
+
expect { double.use }.to raise_error(/private method `use' called/)
|
23
|
+
|
24
|
+
double = Module.new { TestDouble.extend_onto(self) }
|
25
|
+
double.should_receive(:use).and_return(:ok)
|
26
|
+
expect(double.use).to be(:ok)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'sets the test double name when a name is passed' do
|
30
|
+
double = Module.new { TestDouble.extend_onto(self, "MyDouble") }
|
31
|
+
expect { double.foo }.to raise_error(/Mock "MyDouble" received/)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'stubs the methods passed in the stubs hash' do
|
35
|
+
double = Module.new do
|
36
|
+
TestDouble.extend_onto(self, "MyDouble", :a => 5, :b => 10)
|
37
|
+
end
|
38
|
+
|
39
|
+
expect(double.a).to eq(5)
|
40
|
+
expect(double.b).to eq(10)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'indicates what type of test double it is in error messages' do
|
44
|
+
double = Module.new do
|
45
|
+
TestDouble.extend_onto(self, "A", :__declared_as => "ModuleMock")
|
46
|
+
end
|
47
|
+
expect { double.foo }.to raise_error(/ModuleMock "A"/)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'is declared as a mock by default' do
|
51
|
+
double = Module.new { TestDouble.extend_onto(self) }
|
52
|
+
expect { double.foo }.to raise_error(/Mock received/)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|