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.
Files changed (46) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +6 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +133 -0
  5. data/Rakefile +8 -0
  6. data/TODO.md +8 -0
  7. data/lib/spy.rb +259 -0
  8. data/lib/spy/double.rb +11 -0
  9. data/lib/spy/dsl.rb +7 -0
  10. data/lib/spy/version.rb +3 -0
  11. data/spec/spec_helper.rb +39 -0
  12. data/spec/spy/and_call_original_spec.rb +152 -0
  13. data/spec/spy/and_yield_spec.rb +114 -0
  14. data/spec/spy/bug_report_10260_spec.rb +8 -0
  15. data/spec/spy/bug_report_10263_spec.rb +24 -0
  16. data/spec/spy/bug_report_496_spec.rb +18 -0
  17. data/spec/spy/bug_report_600_spec.rb +24 -0
  18. data/spec/spy/bug_report_7611_spec.rb +16 -0
  19. data/spec/spy/bug_report_8165_spec.rb +31 -0
  20. data/spec/spy/bug_report_830_spec.rb +21 -0
  21. data/spec/spy/bug_report_957_spec.rb +22 -0
  22. data/spec/spy/double_spec.rb +12 -0
  23. data/spec/spy/failing_argument_matchers_spec.rb +94 -0
  24. data/spec/spy/hash_excluding_matcher_spec.rb +67 -0
  25. data/spec/spy/hash_including_matcher_spec.rb +90 -0
  26. data/spec/spy/mock_spec.rb +734 -0
  27. data/spec/spy/multiple_return_value_spec.rb +119 -0
  28. data/spec/spy/mutate_const_spec.rb +481 -0
  29. data/spec/spy/nil_expectation_warning_spec.rb +56 -0
  30. data/spec/spy/null_object_mock_spec.rb +107 -0
  31. data/spec/spy/options_hash_spec.rb +35 -0
  32. data/spec/spy/partial_mock_spec.rb +196 -0
  33. data/spec/spy/passing_argument_matchers_spec.rb +142 -0
  34. data/spec/spy/precise_counts_spec.rb +68 -0
  35. data/spec/spy/serialization_spec.rb +110 -0
  36. data/spec/spy/stash_spec.rb +54 -0
  37. data/spec/spy/stub_implementation_spec.rb +62 -0
  38. data/spec/spy/stub_spec.rb +85 -0
  39. data/spec/spy/stubbed_message_expectations_spec.rb +47 -0
  40. data/spec/spy/test_double_spec.rb +57 -0
  41. data/spec/spy/to_ary_spec.rb +40 -0
  42. data/spy.gemspec +21 -0
  43. data/test/spy/test_double.rb +19 -0
  44. data/test/test_helper.rb +6 -0
  45. data/test/test_spy.rb +258 -0
  46. 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
+