spy 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  [Docs](http://rdoc.info/gems/spy/frames)
8
8
 
9
- Spy is a lightweight stubbing framework with support for method spies, constant stubs, and object doubles.
9
+ Spy is a lightweight stubbing framework with support for method spies, constant stubs, and object mocks.
10
10
 
11
11
  Spy was designed for 1.9.3+.
12
12
 
@@ -44,6 +44,7 @@ Fail faster, code faster.
44
44
  * #with is not supported
45
45
  * you can usually just check the call logs.
46
46
  * if you do need to use this. It is probably a code smell. You either need to abstract your method more or add separate tests.
47
+ * you want to use dumb double, Spy has smart mocks, they are better
47
48
  * you use `mock_model` and `stub_model` (I want to impliment this soon)
48
49
 
49
50
  ## Installation
@@ -93,20 +94,26 @@ Book.new(title: "Siddhartha").title #=> "Cannery Row"
93
94
  Book.new(title: "The Big Cheese").title #=> "Cannery Row"
94
95
  ```
95
96
 
96
- ### Test Doubles
97
+ ### Test Mocks
97
98
 
98
- A test double is an object that stands in for a real object.
99
+ A test mock is an object that quacks like a given class but will raise an error
100
+ when the method is not stubbed. You can spy on the classes and call through to
101
+ the original method.
99
102
 
100
103
  ```ruby
101
- Spy.double("book")
102
- ```
104
+ book = Spy.mock(Book)
105
+ Spy.on(book, first_name: "Neil", last_name: "Gaiman")
106
+ Spy.on(book, :author).and_call_through
107
+ book.author #=> "Neil Gaiman"
103
108
 
104
- Spy will let you stub on any method even if it doesn't exist if the object is a double.
109
+ book.responds_to? :title #=> true
110
+ book.title #=> Spy::NeverHookedError: 'title' was never hooked on mock spy.
111
+ ```
105
112
 
106
- Spy comes with a shortcut to define an object with methods.
113
+ To stub methods during instantiation just add arguments.
107
114
 
108
115
  ```ruby
109
- Spy.double("book", title: "Grapes of Wrath", author: "John Steinbeck")
116
+ book = Spy.mock(book, :first_name, author: "Neil Gaiman")
110
117
  ```
111
118
 
112
119
  ### Arbitrary Handling
data/lib/spy/agency.rb CHANGED
@@ -22,8 +22,7 @@ module Spy
22
22
  # @return [spy]
23
23
  def recruit(spy)
24
24
  raise AlreadyStubbedError if @spies[spy.object_id]
25
- case spy
26
- when Subroutine, Constant, Double
25
+ if spy.is_a? Base
27
26
  @spies[spy.object_id] = spy
28
27
  else
29
28
  raise ArgumentError, "#{spy}, was not a spy"
@@ -35,8 +34,7 @@ module Spy
35
34
  # @return [spy]
36
35
  def retire(spy)
37
36
  raise NoSpyError unless @spies[spy.object_id]
38
- case spy
39
- when Subroutine, Constant, Double
37
+ if spy.is_a? Base
40
38
  @spies.delete(spy.object_id)
41
39
  else
42
40
  raise ArgumentError, "#{spy}, was not a spy"
@@ -47,8 +45,7 @@ module Spy
47
45
  # @param spy [Subroutine, Constant, Double]
48
46
  # @return [Boolean]
49
47
  def active?(spy)
50
- case spy
51
- when Subroutine, Constant, Double
48
+ if spy.is_a? Base
52
49
  @spies.has_key?(spy.object_id)
53
50
  else
54
51
  raise ArgumentError, "#{spy}, was not a spy"
data/lib/spy/base.rb ADDED
@@ -0,0 +1,4 @@
1
+ module Spy
2
+ module Base
3
+ end
4
+ end
data/lib/spy/constant.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Spy
2
2
  class Constant
3
-
3
+ include Base
4
4
  # @!attribute [r] base_module
5
5
  # @return [Module] the module that is being watched
6
6
  #
@@ -2,32 +2,32 @@ module Spy
2
2
  class Error < StandardError; end
3
3
 
4
4
  class AlreadyStubbedError < Error
5
- def message
6
- "Spy is already stubbed."
5
+ def to_s
6
+ @mesg || "Spy is already stubbed."
7
7
  end
8
8
  end
9
9
 
10
10
  class AlreadyHookedError < Error
11
- def message
12
- "Spy is already hooked."
11
+ def to_s
12
+ @mesg || "Spy is already hooked."
13
13
  end
14
14
  end
15
15
 
16
16
  class NotHookedError < Error
17
- def message
18
- "Spy was not hooked."
17
+ def to_s
18
+ @mesg || "Spy was not hooked."
19
19
  end
20
20
  end
21
21
 
22
22
  class NeverHookedError < Error
23
- def message
24
- "Spy was never hooked."
23
+ def to_s
24
+ @mesg || "Spy was never hooked."
25
25
  end
26
26
  end
27
27
 
28
28
  class NoSpyError < Error
29
- def message
30
- "Spy could not be found"
29
+ def to_s
30
+ @mesg || "Spy could not be found"
31
31
  end
32
32
  end
33
33
  end
data/lib/spy/mock.rb ADDED
@@ -0,0 +1,122 @@
1
+ module Spy
2
+ # A Mock is an object that has all the same methods as the given class.
3
+ # Each method however will raise a NeverHookedError if it hasn't been stubbed.
4
+ # If you attempt to stub a method on the mock that doesn't exist on the
5
+ # original class it will raise an error.
6
+ module Mock
7
+ include Base
8
+ CLASSES_NOT_TO_OVERRIDE = [Enumerable, Numeric, Comparable, Class, Module, Object]
9
+ METHODS_NOT_TO_OVERRIDE = [:initialize, :method]
10
+
11
+ def initialize
12
+ end
13
+
14
+ def is_a?(other)
15
+ self.class.ancestors.include?(other)
16
+ end
17
+
18
+ alias :kind_of? :is_a?
19
+
20
+ def instance_of?(other)
21
+ other == self.class
22
+ end
23
+
24
+ def method(method_name)
25
+ new_method = super
26
+ if new_method.parameters.size >= 1 &&
27
+ new_method.parameters.last.last == :never_hooked
28
+
29
+ begin
30
+ _mock_class.send(:remove_method, method_name)
31
+ real_method = super
32
+ ensure
33
+ _mock_class.send(:define_method, method_name, new_method)
34
+ end
35
+
36
+ real_method
37
+ else
38
+ new_method
39
+ end
40
+ end
41
+
42
+ class << self
43
+ def new(klass)
44
+ mock_klass = Class.new(klass)
45
+ mock_klass.class_exec do
46
+ alias :_mock_class :class
47
+ private :_mock_class
48
+
49
+ define_method(:class) do
50
+ klass
51
+ end
52
+
53
+ include Mock
54
+ end
55
+ Agency.instance.recruit(mock_klass)
56
+ mock_klass
57
+ end
58
+
59
+ def included(mod)
60
+ method_classes = classes_to_override_methods(mod)
61
+
62
+ mocked_methods = []
63
+ [:public, :protected, :private].each do |visibility|
64
+ get_inherited_methods(method_classes, visibility).each do |method_name|
65
+ mocked_methods << method_name
66
+ args = args_for_method(mod.instance_method(method_name))
67
+
68
+ mod.class_eval <<-DEF_METHOD, __FILE__, __LINE__+1
69
+ def #{method_name}(#{args})
70
+ raise ::Spy::NeverHookedError, "'#{method_name}' was never hooked on mock spy."
71
+ end
72
+
73
+ #{visibility} :#{method_name}
74
+ DEF_METHOD
75
+ end
76
+ end
77
+
78
+ mod.define_singleton_method(:mocked_methods) do
79
+ mocked_methods
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ def classes_to_override_methods(mod)
86
+ method_classes = mod.ancestors
87
+ method_classes.shift
88
+ method_classes.delete(self)
89
+ CLASSES_NOT_TO_OVERRIDE.each do |klass|
90
+ index = method_classes.index(klass)
91
+ method_classes.slice!(index..-1) if index
92
+ end
93
+ method_classes
94
+ end
95
+
96
+ def get_inherited_methods(klass_ancestors, visibility)
97
+ instance_methods = klass_ancestors.map do |klass|
98
+ klass.send("#{visibility}_instance_methods".to_sym, false)
99
+ end
100
+ instance_methods.flatten!
101
+ instance_methods.uniq!
102
+ instance_methods - METHODS_NOT_TO_OVERRIDE
103
+ end
104
+
105
+ def args_for_method(method)
106
+ args = method.parameters.map do |type,name|
107
+ name ||= :args
108
+ case type
109
+ when :req
110
+ name
111
+ when :opt
112
+ "#{name} = nil"
113
+ when :rest
114
+ "*#{name}"
115
+ end
116
+ end.compact
117
+ args << "&never_hooked"
118
+ args.join(",")
119
+ end
120
+ end
121
+ end
122
+ end
@@ -1,5 +1,6 @@
1
1
  module Spy
2
2
  class Subroutine
3
+ include Base
3
4
  # @!attribute [r] base_object
4
5
  # @return [Object] the object that is being watched
5
6
  #
@@ -45,7 +46,6 @@ module Spy
45
46
  @hook_opts = opts
46
47
  @original_method_visibility = method_visibility_of(method_name)
47
48
  hook_opts[:visibility] ||= original_method_visibility
48
- hook_opts[:force] ||= base_object.is_a?(Double)
49
49
 
50
50
  if original_method_visibility || !hook_opts[:force]
51
51
  @original_method = current_method
@@ -361,14 +361,11 @@ module Spy
361
361
  end.compact
362
362
  end
363
363
 
364
- private
365
-
364
+ # @private
366
365
  def get_spy_id(method)
367
366
  return nil unless method.parameters[0].is_a?(Array)
368
- first_param_name = method.parameters[0][1].to_s
369
- if first_param_name.include?("__spy_args")
370
- first_param_name.split("_").last.to_i
371
- end
367
+ id = method.parameters[0][1].to_s.sub!("__spy_args_", "")
368
+ id.to_i if id
372
369
  end
373
370
  end
374
371
  end
data/lib/spy/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Spy
2
- VERSION = "0.2.5"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/spy.rb CHANGED
@@ -1,9 +1,10 @@
1
1
  require "spy/core_ext/marshal"
2
2
  require "spy/agency"
3
+ require "spy/base"
3
4
  require "spy/call_log"
4
5
  require "spy/constant"
5
- require "spy/double"
6
6
  require "spy/exceptions"
7
+ require "spy/mock"
7
8
  require "spy/nest"
8
9
  require "spy/subroutine"
9
10
  require "spy/version"
@@ -107,17 +108,31 @@ module Spy
107
108
  spies.size > 1 ? spies : spies.first
108
109
  end
109
110
 
111
+ def mock(klass, *stubs)
112
+ new_mock = Mock.new(klass).new
113
+ if stubs.size > 0
114
+ on(new_mock, *stubs)
115
+ end
116
+ new_mock
117
+ end
118
+
119
+ def mock_all(klass, *stubs)
120
+ mock_klass = Mock.new(klass)
121
+ new_mock = mock_klass.new
122
+
123
+ spies = stubs.size > 0 ? on(new_mock, *stubs) : []
124
+
125
+ unstubbed_methods = mock_klass.mocked_methods - spies.map(&:method_name)
126
+ on(new_mock, *unstubbed_methods) if unstubbed_methods.size > 0
127
+
128
+ new_mock
129
+ end
130
+
110
131
  # unhook all methods
111
132
  def teardown
112
133
  Agency.instance.dissolve!
113
134
  end
114
135
 
115
- # returns a double
116
- # (see Double#initizalize)
117
- def double(*args)
118
- Double.new(*args)
119
- end
120
-
121
136
  # retrieve the spy from an object
122
137
  # @param base_object
123
138
  # @param method_names *[Symbol]
@@ -16,14 +16,9 @@ class TestSubClass < TestClass
16
16
  P = :p
17
17
  end
18
18
 
19
- require "rspec/mocks/mutate_const"
20
-
21
19
  module Spy
22
20
  describe "Constant Mutating" do
23
21
 
24
- require "rspec/mocks/mutate_const"
25
- include RSpec::Mocks::RecursiveConstMethods
26
-
27
22
  def reset_rspec_mocks
28
23
  Spy.teardown
29
24
  end
@@ -360,9 +355,6 @@ module Spy
360
355
  end
361
356
 
362
357
  describe Constant do
363
- require "rspec/mocks/mutate_const"
364
- include RSpec::Mocks::RecursiveConstMethods
365
-
366
358
  def reset_rspec_mocks
367
359
  Spy.teardown
368
360
  end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ class TestMocking < MiniTest::Unit::TestCase
4
+ def teardown
5
+ Spy::Agency.instance.dissolve!
6
+ end
7
+
8
+ def test_spy_on_mock_does_not_raise
9
+ mock = Spy.mock(Pen)
10
+ spy = Spy.on(mock, :write).and_return(:awesome)
11
+ assert_equal :awesome, mock.write("hello")
12
+ assert spy.has_been_called?
13
+ end
14
+
15
+ def test_spy_mock_shortcuts
16
+ mock = Spy.mock(Pen, :another, write_hello: :goodbye)
17
+ assert_nil mock.another
18
+ assert_equal :goodbye, mock.write_hello
19
+ end
20
+
21
+ def test_spy_mock_all
22
+ mock = Spy.mock_all(Pen)
23
+ assert_nil mock.another
24
+ end
25
+ end
@@ -39,5 +39,4 @@ class TestSpy < MiniTest::Unit::TestCase
39
39
  assert_equal "hello world", @pen.write("hello world")
40
40
  refute pen_write_spy.has_been_called?
41
41
  end
42
-
43
42
  end
@@ -0,0 +1,88 @@
1
+ require 'test_helper'
2
+
3
+ module Spy
4
+ class TestMock < MiniTest::Unit::TestCase
5
+ class BluePen < Pen
6
+ def write_hello(other)
7
+ end
8
+ end
9
+
10
+ def setup
11
+ @pen_mock = Mock.new(BluePen)
12
+ @pen = @pen_mock.new
13
+ end
14
+
15
+ def teardown
16
+ Spy::Agency.instance.dissolve!
17
+ end
18
+
19
+ def test_class_methods
20
+ assert @pen.kind_of?(BluePen)
21
+ assert @pen.kind_of?(Pen)
22
+ assert @pen.is_a?(Pen)
23
+ assert @pen.is_a?(BluePen)
24
+ assert @pen.instance_of?(BluePen)
25
+ assert_equal BluePen, @pen.class
26
+ end
27
+
28
+ def test_raises_error_on_unstubbed_method
29
+ assert_raises Spy::NeverHookedError do
30
+ @pen.write("")
31
+ end
32
+ end
33
+
34
+ def test_mimics_visibility
35
+ assert @pen.singleton_class.public_method_defined? :public_method
36
+ assert @pen.singleton_class.protected_method_defined? :protected_method
37
+ assert @pen.singleton_class.private_method_defined? :private_method
38
+ end
39
+
40
+ def test_that_method_spy_keeps_arity
41
+ assert_raises ArgumentError do
42
+ @pen.write
43
+ end
44
+
45
+ assert_raises ArgumentError do
46
+ @pen.write("hello", "world")
47
+ end
48
+
49
+ assert_raises ArgumentError do
50
+ @pen.write_hello
51
+ end
52
+
53
+ assert_raises ArgumentError do
54
+ @pen.greet
55
+ end
56
+
57
+ assert_raises ArgumentError do
58
+ @pen.greet("hello", "bob", "error")
59
+ end
60
+ end
61
+
62
+ def test_that_and_call_original_works
63
+ Spy.on(@pen, :another).and_call_through
64
+ assert_equal "another", @pen.another
65
+ Spy.off(@pen, :another)
66
+ assert_raises Spy::NeverHookedError do
67
+ @pen.another
68
+ end
69
+ end
70
+
71
+ def test_mocked_methods
72
+ pen_methods = Pen.public_instance_methods(false) +
73
+ Pen.protected_instance_methods(false) +
74
+ Pen.private_instance_methods(false)
75
+ pen_methods.delete(:initialize)
76
+ assert_equal pen_methods.sort, @pen_mock.mocked_methods.sort
77
+ end
78
+
79
+ def test_base_class_methods_are_not_stubbed
80
+ (Object.instance_methods - [:tap, :pretty_print_inspect]).each do |method_name|
81
+ object_method = Object.instance_method(method_name)
82
+ if object_method.parameters == []
83
+ @pen.send(method_name)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-10 00:00:00.000000000 Z
12
+ date: 2013-03-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pry
@@ -124,11 +124,12 @@ files:
124
124
  - Rakefile
125
125
  - lib/spy.rb
126
126
  - lib/spy/agency.rb
127
+ - lib/spy/base.rb
127
128
  - lib/spy/call_log.rb
128
129
  - lib/spy/constant.rb
129
130
  - lib/spy/core_ext/marshal.rb
130
- - lib/spy/double.rb
131
131
  - lib/spy/exceptions.rb
132
+ - lib/spy/mock.rb
132
133
  - lib/spy/nest.rb
133
134
  - lib/spy/subroutine.rb
134
135
  - lib/spy/version.rb
@@ -138,7 +139,6 @@ files:
138
139
  - spec/spy/any_instance_spec.rb
139
140
  - spec/spy/hash_excluding_matcher_spec.rb
140
141
  - spec/spy/hash_including_matcher_spec.rb
141
- - spec/spy/mock_spec.rb
142
142
  - spec/spy/mutate_const_spec.rb
143
143
  - spec/spy/nil_expectation_warning_spec.rb
144
144
  - spec/spy/null_object_mock_spec.rb
@@ -152,8 +152,9 @@ files:
152
152
  - spy.gemspec
153
153
  - test/integration/test_constant_spying.rb
154
154
  - test/integration/test_instance_method.rb
155
+ - test/integration/test_mocking.rb
155
156
  - test/integration/test_subroutine_spying.rb
156
- - test/spy/test_double.rb
157
+ - test/spy/test_mock.rb
157
158
  - test/spy/test_subroutine.rb
158
159
  - test/support/pen.rb
159
160
  - test/test_helper.rb
@@ -191,7 +192,6 @@ test_files:
191
192
  - spec/spy/any_instance_spec.rb
192
193
  - spec/spy/hash_excluding_matcher_spec.rb
193
194
  - spec/spy/hash_including_matcher_spec.rb
194
- - spec/spy/mock_spec.rb
195
195
  - spec/spy/mutate_const_spec.rb
196
196
  - spec/spy/nil_expectation_warning_spec.rb
197
197
  - spec/spy/null_object_mock_spec.rb
@@ -204,8 +204,9 @@ test_files:
204
204
  - spec/spy/to_ary_spec.rb
205
205
  - test/integration/test_constant_spying.rb
206
206
  - test/integration/test_instance_method.rb
207
+ - test/integration/test_mocking.rb
207
208
  - test/integration/test_subroutine_spying.rb
208
- - test/spy/test_double.rb
209
+ - test/spy/test_mock.rb
209
210
  - test/spy/test_subroutine.rb
210
211
  - test/support/pen.rb
211
212
  - test/test_helper.rb
data/lib/spy/double.rb DELETED
@@ -1,28 +0,0 @@
1
- module Spy
2
- class Double
3
- def initialize(name, *args)
4
- @name = name
5
-
6
- if args.size > 0
7
- Spy.on(self,*args)
8
- end
9
- end
10
-
11
- # @private
12
- def ==(other)
13
- other == self
14
- end
15
-
16
- # @private
17
- def inspect
18
- "#<#{self.class}:#{sprintf '0x%x', self.object_id} @name=#{@name.inspect}>"
19
- end
20
-
21
- # @private
22
- def to_s
23
- inspect.gsub('<','[').gsub('>',']')
24
- end
25
-
26
- alias_method :to_str, :to_s
27
- end
28
- end
@@ -1,222 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Spy
4
- describe Double do
5
- before(:each) { @double = Spy.double("test double") }
6
-
7
- it "has method_missing as private" do
8
- expect(Spy.double("stuff").private_instance_methods).to include_method(:method_missing)
9
- end
10
-
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
14
-
15
- it "fails when receiving message specified as not to be received" do
16
- spy = Spy.on(@double, :not_expected)
17
- expect(spy).to_not have_been_called
18
- end
19
-
20
- it "fails if unexpected method called" do
21
- expect {
22
- @double.something("a","b","c")
23
- }.to raise_error
24
- end
25
-
26
- it "uses block for expectation if provided" do
27
- spy = Spy.on(@double, :something).and_return do | a, b |
28
- expect(a).to eq "a"
29
- expect(b).to eq "b"
30
- "booh"
31
- end
32
- expect(@double.something("a", "b")).to eq "booh"
33
- expect(spy).to have_been_called
34
- end
35
-
36
- it "fails if expectation block fails" do
37
- Spy.on(@double, :something).and_return do | bool|
38
- expect(bool).to be_true
39
- end
40
-
41
- expect {
42
- @double.something false
43
- }.to raise_error(RSpec::Expectations::ExpectationNotMetError)
44
- end
45
-
46
- it "passes proc to expectation block without an argument" do
47
- spy = Spy.on(@double, :foo).and_return do |&block|
48
- expect(block.call).to eq(:bar)
49
- end
50
- @double.foo { :bar }
51
- expect(spy).to have_been_called
52
- end
53
-
54
- it "passes proc to expectation block with an argument" do
55
- spy = Spy.on(@double, :foo).and_return do |arg, &block|
56
- expect(block.call).to eq(:bar)
57
- end
58
- @double.foo(:arg) { :bar }
59
- expect(spy).to have_been_called
60
- end
61
-
62
- it "passes proc to stub block without an argurment" do
63
- spy = Spy.on(@double, :foo).and_return do |&block|
64
- expect(block.call).to eq(:bar)
65
- end
66
- @double.foo { :bar }
67
- expect(spy).to have_been_called
68
- end
69
-
70
- it "passes proc to stub block with an argument" do
71
- spy = Spy.on(@double, :foo) do |arg, &block|
72
- expect(block.call).to eq(:bar)
73
- end
74
- @double.foo(:arg) { :bar }
75
- expect(spy).to have_been_called
76
- end
77
-
78
- it "fails right away when method defined as never is received" do
79
- Spy.on(@double, :not_expected).never
80
- expect { @double.not_expected }.
81
- to raise_error(RSpec::Mocks::MockExpectationError,
82
- %Q|(Double "test double").not_expected(no args)\n expected: 0 times\n received: 1 time|
83
- )
84
- end
85
-
86
- it "raises RuntimeError by default" do
87
- Spy.on(@double, :something).and_raise
88
- expect { @double.something }.to raise_error(RuntimeError)
89
- end
90
-
91
- it "raises RuntimeError with a message by default" do
92
- Spy.on(@double, :something).and_raise("error message")
93
- expect { @double.something }.to raise_error(RuntimeError, "error message")
94
- end
95
-
96
- it "raises an exception of a given type without an error message" do
97
- Spy.on(@double, :something).and_raise(StandardError)
98
- expect { @double.something }.to raise_error(StandardError)
99
- end
100
-
101
- it "raises an exception of a given type with a message" do
102
- Spy.on(@double, :something).and_raise(RuntimeError, "error message")
103
- expect { @double.something }.to raise_error(RuntimeError, "error message")
104
- end
105
-
106
- it "raises a given instance of an exception" do
107
- Spy.on(@double, :something).and_raise(RuntimeError.new("error message"))
108
- expect { @double.something }.to raise_error(RuntimeError, "error message")
109
- end
110
-
111
- class OutOfGas < StandardError
112
- attr_reader :amount, :units
113
- def initialize(amount, units)
114
- @amount = amount
115
- @units = units
116
- end
117
- end
118
-
119
- it "raises a given instance of an exception with arguments other than the standard 'message'" do
120
- Spy.on(@double, :something).and_raise(OutOfGas.new(2, :oz))
121
-
122
- begin
123
- @double.something
124
- fail "OutOfGas was not raised"
125
- rescue OutOfGas => e
126
- expect(e.amount).to eq 2
127
- expect(e.units).to eq :oz
128
- end
129
- end
130
-
131
- it "throws when told to" do
132
- Spy.on(@double, :something).and_throw(:blech)
133
- expect {
134
- @double.something
135
- }.to throw_symbol(:blech)
136
- end
137
-
138
- it "returns value from block by default" do
139
- spy = Spy.on(@double, :method_that_yields).and_yield
140
- value = @double.method_that_yields { :returned_obj }
141
- expect(value).to eq :returned_obj
142
- expect(spy).to have_been_called
143
- end
144
-
145
- it "is able to raise from method calling yielding double" do
146
- spy = Spy.on(@double, :yield_me).and_yield 44
147
-
148
- expect {
149
- @double.yield_me do |x|
150
- raise "Bang"
151
- end
152
- }.to raise_error(StandardError, "Bang")
153
-
154
- expect(spy).to have_been_called
155
- end
156
-
157
- it "assigns stub return values" do
158
- double = Spy.double('name', :message => :response)
159
- expect(double.message).to eq :response
160
- end
161
-
162
- end
163
-
164
- describe "a double message receiving a block" do
165
- before(:each) do
166
- @double = Spy.double("double")
167
- @calls = 0
168
- end
169
-
170
- def add_call
171
- @calls = @calls + 1
172
- end
173
-
174
- it "calls the block after #should_receive" do
175
- spy = Spy.on(@double, :foo).and_return { add_call }
176
-
177
- @double.foo
178
-
179
- expect(@calls).to eq 1
180
- expect(spy).to have_been_called
181
- end
182
- end
183
-
184
- describe 'string representation generated by #to_s' do
185
- it 'does not contain < because that might lead to invalid HTML in some situations' do
186
- double = Spy.double("Dog")
187
- valid_html_str = "#{double}"
188
- expect(valid_html_str).not_to include('<')
189
- end
190
- end
191
-
192
- describe "string representation generated by #to_str" do
193
- it "looks the same as #to_s" do
194
- double = Spy.double("Foo")
195
- expect(double.to_str).to eq double.to_s
196
- end
197
- end
198
-
199
- describe "double created with no name" do
200
- it "does not use a name in a failure message" do
201
- double = Spy.double()
202
- expect {double.foo}.to raise_error(/Double received/)
203
- end
204
-
205
- it "does respond to initially stubbed methods" do
206
- double = Spy.double("name", :foo => "woo", :bar => "car")
207
- expect(double.foo).to eq "woo"
208
- expect(double.bar).to eq "car"
209
- end
210
- end
211
-
212
- describe "==" do
213
- it "sends '== self' to the comparison object" do
214
- first = Spy.double('first')
215
- second = Spy.double('second')
216
-
217
- spy = Spy.on(first, :==)
218
- second == first
219
- expect(spy.calls.first.args).to eq([second])
220
- end
221
- end
222
- end
@@ -1,23 +0,0 @@
1
- require 'test_helper'
2
-
3
- module Spy
4
- class TestDouble < MiniTest::Unit::TestCase
5
- def teardown
6
- Spy::Agency.instance.dissolve!
7
- end
8
-
9
- def test_double_creation
10
- double = Double.new("NewDouble", :meth_1, :meth_2)
11
-
12
- assert_nil double.meth_1
13
- assert_nil double.meth_2
14
- end
15
-
16
- def test_double_hash_input
17
- double = Double.new("NewDouble", meth_1: :meth_1, meth_2: :meth_2)
18
-
19
- assert_equal :meth_1, double.meth_1
20
- assert_equal :meth_2, double.meth_2
21
- end
22
- end
23
- end