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
@@ -1,109 +1,115 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'yaml'
|
3
|
+
require 'psych'
|
4
|
+
require 'syck'
|
2
5
|
|
3
|
-
module
|
4
|
-
|
5
|
-
describe Serialization do
|
6
|
+
module Spy
|
7
|
+
describe "serialization" do
|
6
8
|
|
7
|
-
|
9
|
+
class SerializableObject < Struct.new(:foo, :bar); end
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
+
class SerializableMockProxy
|
12
|
+
attr_reader :mock_proxy
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
def initialize(mock_proxy)
|
15
|
+
@mock_proxy = mock_proxy
|
16
|
+
end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
end
|
18
|
+
def ==(other)
|
19
|
+
other.class == self.class && other.mock_proxy == mock_proxy
|
19
20
|
end
|
21
|
+
end
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
23
|
+
def self.with_yaml_loaded(&block)
|
24
|
+
context 'with YAML loaded' do
|
25
|
+
module_eval(&block)
|
25
26
|
end
|
27
|
+
end
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
29
|
+
def self.without_yaml_loaded(&block)
|
30
|
+
context 'without YAML loaded' do
|
31
|
+
before do
|
32
|
+
# We can't really unload yaml, but we can fake it here...
|
33
|
+
@yaml = YAML
|
34
|
+
Object.send(:remove_const, "YAML")
|
35
|
+
Struct.class_eval do
|
36
|
+
alias __old_to_yaml to_yaml
|
37
|
+
undef to_yaml
|
36
38
|
end
|
39
|
+
end
|
37
40
|
|
38
|
-
|
41
|
+
module_eval(&block)
|
39
42
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
43
|
+
after do
|
44
|
+
Struct.class_eval do
|
45
|
+
alias to_yaml __old_to_yaml
|
46
|
+
undef __old_to_yaml
|
45
47
|
end
|
48
|
+
|
49
|
+
Object.send(:const_set, "YAML", @yaml)
|
46
50
|
end
|
47
51
|
end
|
52
|
+
end
|
48
53
|
|
49
|
-
|
54
|
+
let(:serializable_object) { SerializableObject.new(7, "something") }
|
50
55
|
|
51
|
-
|
52
|
-
|
53
|
-
|
56
|
+
def set_spy
|
57
|
+
Spy::Subroutine.new(serializable_object, :bazz).hook(force: true).and_return(5)
|
58
|
+
end
|
54
59
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
60
|
+
shared_examples_for 'normal YAML serialization' do
|
61
|
+
it 'serializes to yaml the same with and without stubbing, using #to_yaml' do
|
62
|
+
set_spy
|
63
|
+
expect { Spy.get(serializable_object, :bazz) }.to_not change { serializable_object.to_yaml }
|
64
|
+
end
|
59
65
|
|
60
|
-
|
61
|
-
|
62
|
-
|
66
|
+
it 'serializes to yaml the same with and without stubbing, using YAML.dump' do
|
67
|
+
set_spy
|
68
|
+
expect { Spy.get(serializable_object, :bazz) }.to_not change { ::YAML.dump(serializable_object) }
|
63
69
|
end
|
70
|
+
end
|
64
71
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
72
|
+
with_yaml_loaded do
|
73
|
+
compiled_with_psych = begin
|
74
|
+
require 'psych'
|
75
|
+
true
|
76
|
+
rescue LoadError
|
77
|
+
false
|
78
|
+
end
|
79
|
+
|
80
|
+
if compiled_with_psych
|
81
|
+
context 'using Syck as the YAML engine' do
|
82
|
+
before(:each) { ::YAML::ENGINE.yamler = 'syck' }
|
83
|
+
it_behaves_like 'normal YAML serialization'
|
71
84
|
end
|
72
85
|
|
73
|
-
|
74
|
-
|
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
|
86
|
+
context 'using Psych as the YAML engine' do
|
87
|
+
before(:each) { ::YAML::ENGINE.yamler = 'psych' }
|
84
88
|
it_behaves_like 'normal YAML serialization'
|
85
89
|
end
|
90
|
+
else
|
91
|
+
it_behaves_like 'normal YAML serialization'
|
86
92
|
end
|
93
|
+
end
|
87
94
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
95
|
+
without_yaml_loaded do
|
96
|
+
it 'does not add #to_yaml to the stubbed object' do
|
97
|
+
expect(serializable_object).not_to respond_to(:to_yaml)
|
98
|
+
set_spy
|
99
|
+
expect(serializable_object).not_to respond_to(:to_yaml)
|
94
100
|
end
|
101
|
+
end
|
95
102
|
|
96
|
-
|
97
|
-
|
98
|
-
|
103
|
+
it 'marshals the same with and without stubbing' do
|
104
|
+
expect { Spy.get(serializable_object, :bazz) }.to_not change { Marshal.dump(serializable_object) }
|
105
|
+
end
|
99
106
|
|
100
|
-
|
101
|
-
|
107
|
+
describe "an object that has its own mock_proxy instance variable" do
|
108
|
+
let(:serializable_object) { SerializableMockProxy.new(:my_mock_proxy) }
|
102
109
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
end
|
110
|
+
it 'does not interfere with its marshalling' do
|
111
|
+
marshalled_copy = Marshal.load(Marshal.dump(serializable_object))
|
112
|
+
expect(marshalled_copy).to eq serializable_object
|
107
113
|
end
|
108
114
|
end
|
109
115
|
end
|
@@ -1,28 +1,31 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
module
|
4
|
-
|
3
|
+
module Spy
|
4
|
+
describe Subroutine do
|
5
|
+
class Bar
|
6
|
+
def foo(given = nil)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:obj) { Bar.new }
|
5
11
|
describe "stub implementation" do
|
6
12
|
describe "with no args" do
|
7
13
|
it "execs the block when called" do
|
8
|
-
obj
|
9
|
-
Spy.stub(obj, :foo).and_return { :bar }
|
14
|
+
Subroutine.new(obj, :foo).hook.and_return { :bar }
|
10
15
|
expect(obj.foo).to eq :bar
|
11
16
|
end
|
12
17
|
end
|
13
18
|
|
14
19
|
describe "with one arg" do
|
15
20
|
it "execs the block with that arg when called" do
|
16
|
-
obj
|
17
|
-
Spy.stub(obj, :foo).and_return {|given| given}
|
21
|
+
Subroutine.new(obj, :foo).hook.and_return {|given| given}
|
18
22
|
expect(obj.foo(:bar)).to eq :bar
|
19
23
|
end
|
20
24
|
end
|
21
25
|
|
22
26
|
describe "with variable args" do
|
23
27
|
it "execs the block when called" do
|
24
|
-
obj
|
25
|
-
Spy.stub(obj, :foo).and_return {|*given| given.first}
|
28
|
+
Subroutine.new(obj, :foo).hook.and_return {|*given| given.first}
|
26
29
|
expect(obj.foo(:bar)).to eq :bar
|
27
30
|
end
|
28
31
|
end
|
@@ -33,8 +36,7 @@ module RSpec
|
|
33
36
|
it "replaces the stubbed method with the original method" do
|
34
37
|
obj = Object.new
|
35
38
|
def obj.foo; :original; end
|
36
|
-
|
37
|
-
Spy.off(obj, :foo)
|
39
|
+
Subroutine.new(obj, :foo).hook.unhook
|
38
40
|
expect(obj.foo).to eq :original
|
39
41
|
end
|
40
42
|
|
@@ -42,8 +44,8 @@ module RSpec
|
|
42
44
|
parent = Class.new
|
43
45
|
child = Class.new(parent)
|
44
46
|
|
45
|
-
Spy.
|
46
|
-
Spy.
|
47
|
+
Spy.on(parent, :new)
|
48
|
+
Spy.on(child, :new)
|
47
49
|
Spy.off(parent, :new)
|
48
50
|
Spy.off(child, :new)
|
49
51
|
|
data/spec/spy/stub_spec.rb
CHANGED
@@ -29,55 +29,55 @@ module RSpec
|
|
29
29
|
@stub = Object.new
|
30
30
|
end
|
31
31
|
|
32
|
-
describe "using Spy.
|
32
|
+
describe "using Spy::Subroutine.new" do
|
33
33
|
it "returns declared value when message is received" do
|
34
|
-
Spy.
|
34
|
+
Spy::Subroutine.new(@instance, :msg).hook(force: true).and_return(:return_value)
|
35
35
|
expect(@instance.msg).to equal(:return_value)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
39
|
it "instructs an instance to respond_to the message" do
|
40
|
-
Spy.
|
40
|
+
Spy::Subroutine.new(@instance, :msg).hook(force: true)
|
41
41
|
expect(@instance).to respond_to(:msg)
|
42
42
|
end
|
43
43
|
|
44
44
|
it "instructs a class object to respond_to the message" do
|
45
|
-
Spy.
|
45
|
+
Spy::Subroutine.new(@class, :msg).hook(force: true)
|
46
46
|
expect(@class).to respond_to(:msg)
|
47
47
|
end
|
48
48
|
|
49
49
|
it "handles multiple stubbed methods" do
|
50
|
-
Spy.
|
50
|
+
Spy::Subroutine.new(@instance, :msg1 => 1, :msg2 => 2).hook(force: true)
|
51
51
|
expect(@instance.msg1).to eq(1)
|
52
52
|
expect(@instance.msg2).to eq(2)
|
53
53
|
end
|
54
54
|
|
55
55
|
it "yields a specified object" do
|
56
|
-
Spy.
|
56
|
+
Spy::Subroutine.new(@instance, :method_that_yields).hook(force: true).and_yield(:yielded_obj)
|
57
57
|
current_value = :value_before
|
58
58
|
@instance.method_that_yields {|val| current_value = val}
|
59
59
|
expect(current_value).to eq :yielded_obj
|
60
60
|
end
|
61
61
|
|
62
62
|
it "yields a specified object and return another specified object" do
|
63
|
-
yielded_obj = double("my mock")
|
64
|
-
Spy.
|
65
|
-
Spy.
|
63
|
+
yielded_obj = Spy.double("my mock")
|
64
|
+
Spy::Subroutine.new(yielded_obj, :foo).hook(force: true)
|
65
|
+
Spy::Subroutine.new(@instance, :method_that_yields_and_returns).hook(force: true).and_yield(yielded_obj).and_return(:baz)
|
66
66
|
expect(@instance.method_that_yields_and_returns { |o| o.foo :bar }).to eq :baz
|
67
67
|
end
|
68
68
|
|
69
69
|
it "throws when told to" do
|
70
|
-
Spy.
|
70
|
+
Spy::Subroutine.new(@stub, :something).hook(force: true).and_throw(:up)
|
71
71
|
expect { @stub.something }.to throw_symbol(:up)
|
72
72
|
end
|
73
73
|
|
74
74
|
it "throws with argument when told to" do
|
75
|
-
Spy.
|
75
|
+
Spy::Subroutine.new(@stub, :something).hook(force: true).and_throw(:up, 'high')
|
76
76
|
expect { @stub.something }.to throw_symbol(:up, 'high')
|
77
77
|
end
|
78
78
|
|
79
79
|
it "overrides a pre-existing method" do
|
80
|
-
Spy.
|
80
|
+
Spy::Subroutine.new(@stub, :existing_instance_method).hook(force: true).and_return(:updated_stub_value)
|
81
81
|
expect(@stub.existing_instance_method).to eq :updated_stub_value
|
82
82
|
end
|
83
83
|
end
|
@@ -1,57 +1,54 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def use; end
|
10
|
-
end
|
3
|
+
module Spy
|
4
|
+
describe Double do
|
5
|
+
before(:all) do
|
6
|
+
Module.class_eval do
|
7
|
+
private
|
8
|
+
def use; end
|
11
9
|
end
|
10
|
+
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
12
|
+
after(:all) do
|
13
|
+
Module.class_eval do
|
14
|
+
undef use
|
17
15
|
end
|
16
|
+
end
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
18
|
+
it 'can be extended onto a module to make it a pure test double that can mock private methods' do
|
19
|
+
double = Module.new
|
20
|
+
Spy.on(double, :use)
|
21
|
+
expect { double.use }.to raise_error(/private method `use' called/)
|
28
22
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
23
|
+
double = Module.new { TestDouble.extend_onto(self) }
|
24
|
+
double.should_receive(:use).and_return(:ok)
|
25
|
+
expect(double.use).to be(:ok)
|
26
|
+
end
|
33
27
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
28
|
+
it 'sets the test double name when a name is passed' do
|
29
|
+
double = Module.new { TestDouble.extend_onto(self, "MyDouble") }
|
30
|
+
expect { double.foo }.to raise_error(/Mock "MyDouble" received/)
|
31
|
+
end
|
38
32
|
|
39
|
-
|
40
|
-
|
33
|
+
it 'stubs the methods passed in the stubs hash' do
|
34
|
+
double = Module.new do
|
35
|
+
TestDouble.extend_onto(self, "MyDouble", :a => 5, :b => 10)
|
41
36
|
end
|
42
37
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
expect { double.foo }.to raise_error(/ModuleMock "A"/)
|
48
|
-
end
|
38
|
+
expect(double.a).to eq(5)
|
39
|
+
expect(double.b).to eq(10)
|
40
|
+
end
|
49
41
|
|
50
|
-
|
51
|
-
|
52
|
-
|
42
|
+
it 'indicates what type of test double it is in error messages' do
|
43
|
+
double = Module.new do
|
44
|
+
TestDouble.extend_onto(self, "A", :__declared_as => "ModuleMock")
|
53
45
|
end
|
46
|
+
expect { double.foo }.to raise_error(/ModuleMock "A"/)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'is declared as a mock by default' do
|
50
|
+
double = Module.new { TestDouble.extend_onto(self) }
|
51
|
+
expect { double.foo }.to raise_error(/Mock received/)
|
54
52
|
end
|
55
53
|
end
|
56
54
|
end
|
57
|
-
|
data/spy.gemspec
CHANGED
@@ -17,5 +17,6 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
gem.add_development_dependency('minitest', '>= 4.5.0')
|
20
|
-
gem.add_development_dependency('rspec')
|
20
|
+
gem.add_development_dependency('rspec-core')
|
21
|
+
gem.add_development_dependency('rspec-expectations')
|
21
22
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestConstantSpying < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
class Foo
|
6
|
+
HELLO = "hello world"
|
7
|
+
|
8
|
+
def self.hello
|
9
|
+
HELLO
|
10
|
+
end
|
11
|
+
|
12
|
+
module Bar
|
13
|
+
def self.hello
|
14
|
+
HELLO
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class ChildFoo < Foo
|
20
|
+
def self.hello
|
21
|
+
HELLO
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup
|
26
|
+
Spy::Agency.instance.dissolve!
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_spy_on_constant
|
30
|
+
assert_equal "hello world", Foo.hello
|
31
|
+
|
32
|
+
spy = Spy.on_const(Foo, :HELLO)
|
33
|
+
assert_equal nil, Foo.hello
|
34
|
+
spy.and_return("awesome")
|
35
|
+
assert_equal "awesome", Foo.hello
|
36
|
+
|
37
|
+
Spy.off_const(Foo, :HELLO)
|
38
|
+
assert_equal "hello world", Foo.hello
|
39
|
+
|
40
|
+
assert_equal "hello world", Foo::Bar.hello
|
41
|
+
spy = Spy.on_const(Foo, :HELLO)
|
42
|
+
assert_equal nil, Foo::Bar.hello
|
43
|
+
spy.and_return("awesome")
|
44
|
+
assert_equal "awesome", Foo::Bar.hello
|
45
|
+
|
46
|
+
Spy.off_const(Foo, :HELLO)
|
47
|
+
assert_equal "hello world", Foo::Bar.hello
|
48
|
+
|
49
|
+
assert_equal "hello world", ChildFoo.hello
|
50
|
+
spy = Spy.on_const(Foo, :HELLO)
|
51
|
+
assert_equal nil, ChildFoo.hello
|
52
|
+
spy.and_return("awesome")
|
53
|
+
assert_equal "awesome", ChildFoo.hello
|
54
|
+
|
55
|
+
Spy.off_const(Foo, :HELLO)
|
56
|
+
assert_equal "hello world", ChildFoo.hello
|
57
|
+
end
|
58
|
+
end
|