spy 0.2.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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