rspec-mocks 2.0.0.beta.4 → 2.0.0.beta.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +3 -2
- data/VERSION +1 -1
- data/features/mocks/block_local_expectations.feature +0 -14
- data/features/mocks/mix_stubs_and_mocks.feature +2 -2
- data/features/mocks/warn_when_expectation_is_set_on_nil.feature +50 -0
- data/lib/rspec/mocks.rb +9 -9
- data/lib/rspec/mocks/argument_matchers.rb +1 -1
- data/lib/rspec/mocks/error_generator.rb +24 -8
- data/lib/rspec/mocks/framework.rb +1 -0
- data/lib/rspec/mocks/message_expectation.rb +1 -1
- data/lib/rspec/mocks/method_double.rb +156 -0
- data/lib/rspec/mocks/methods.rb +2 -2
- data/lib/rspec/mocks/mock.rb +17 -10
- data/lib/rspec/mocks/proxy.rb +71 -158
- data/lib/rspec/mocks/spec_methods.rb +19 -3
- data/rspec-mocks.gemspec +14 -10
- data/spec/rspec/mocks/any_number_of_times_spec.rb +1 -1
- data/spec/rspec/mocks/argument_expectation_spec.rb +2 -2
- data/spec/rspec/mocks/bug_report_10260_spec.rb +1 -1
- data/spec/rspec/mocks/bug_report_10263_spec.rb +8 -8
- data/spec/rspec/mocks/bug_report_15719_spec.rb +12 -12
- data/spec/rspec/mocks/bug_report_7611_spec.rb +1 -1
- data/spec/rspec/mocks/bug_report_7805_spec.rb +1 -1
- data/spec/rspec/mocks/bug_report_8165_spec.rb +1 -1
- data/spec/rspec/mocks/bug_report_957_spec.rb +1 -1
- data/spec/rspec/mocks/double_spec.rb +12 -0
- data/spec/rspec/mocks/failing_argument_matchers_spec.rb +7 -6
- data/spec/rspec/mocks/mock_ordering_spec.rb +54 -54
- data/spec/rspec/mocks/mock_space_spec.rb +4 -4
- data/spec/rspec/mocks/mock_spec.rb +55 -51
- data/spec/rspec/mocks/multiple_return_value_spec.rb +29 -7
- data/spec/rspec/mocks/nil_expectation_warning_spec.rb +8 -8
- data/spec/rspec/mocks/null_object_mock_spec.rb +2 -2
- data/spec/rspec/mocks/once_counts_spec.rb +1 -1
- data/spec/rspec/mocks/options_hash_spec.rb +1 -1
- data/spec/rspec/mocks/partial_mock_spec.rb +13 -7
- data/spec/rspec/mocks/passing_argument_matchers_spec.rb +1 -1
- data/spec/rspec/mocks/precise_counts_spec.rb +1 -1
- data/spec/rspec/mocks/record_messages_spec.rb +1 -1
- data/spec/rspec/mocks/stub_spec.rb +22 -22
- data/spec/rspec/mocks/stubbed_message_expectations_spec.rb +12 -12
- data/spec/rspec/mocks/twice_counts_spec.rb +1 -1
- metadata +13 -9
data/.autotest
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.0.0.beta.
|
1
|
+
2.0.0.beta.5
|
@@ -1,9 +1,5 @@
|
|
1
1
|
Feature: block local expectations
|
2
2
|
|
3
|
-
In order to set message expectations on ...
|
4
|
-
As an RSpec user
|
5
|
-
I want to configure the evaluation context
|
6
|
-
|
7
3
|
Background:
|
8
4
|
Given a file named "account.rb" with:
|
9
5
|
"""
|
@@ -22,13 +18,8 @@ Feature: block local expectations
|
|
22
18
|
"""
|
23
19
|
require 'account'
|
24
20
|
|
25
|
-
Rspec.configure do |config|
|
26
|
-
config.mock_framework = :rspec
|
27
|
-
end
|
28
|
-
|
29
21
|
describe "account DSL" do
|
30
22
|
it "it succeeds when the block local receives the given call" do
|
31
|
-
account = Account.new
|
32
23
|
Account.should_receive(:create).and_yield do |account|
|
33
24
|
account.should_receive(:opening_balance).with(100, :USD)
|
34
25
|
end
|
@@ -47,13 +38,8 @@ Feature: block local expectations
|
|
47
38
|
"""
|
48
39
|
require 'account'
|
49
40
|
|
50
|
-
Rspec.configure do |config|
|
51
|
-
config.mock_framework = :rspec
|
52
|
-
end
|
53
|
-
|
54
41
|
describe "account DSL" do
|
55
42
|
it "fails when the block local does not receive the expected call" do
|
56
|
-
account = Account.new
|
57
43
|
Account.should_receive(:create).and_yield do |account|
|
58
44
|
account.should_receive(:opening_balance).with(100, :USD)
|
59
45
|
end
|
@@ -14,7 +14,7 @@ Feature: Spec and test together
|
|
14
14
|
|
15
15
|
describe "a stub in before" do
|
16
16
|
before(:each) do
|
17
|
-
@messenger =
|
17
|
+
@messenger = double('messenger').as_null_object
|
18
18
|
end
|
19
19
|
|
20
20
|
it "a" do
|
@@ -25,4 +25,4 @@ Feature: Spec and test together
|
|
25
25
|
end
|
26
26
|
"""
|
27
27
|
When I run "rspec stub_and_mocks_spec.rb -fs"
|
28
|
-
Then I should see "
|
28
|
+
Then I should see "received :foo with unexpected arguments"
|
@@ -0,0 +1,50 @@
|
|
1
|
+
Feature: warn when expectation is set on nil
|
2
|
+
|
3
|
+
Scenario: nil instance variable
|
4
|
+
Given a file named "example_spec.rb" with:
|
5
|
+
"""
|
6
|
+
Rspec.configure {|c| c.mock_with :rspec}
|
7
|
+
describe "something" do
|
8
|
+
it "does something" do
|
9
|
+
@i_do_not_exist.should_receive(:foo)
|
10
|
+
@i_do_not_exist.foo
|
11
|
+
end
|
12
|
+
end
|
13
|
+
"""
|
14
|
+
When I run "rspec example_spec.rb"
|
15
|
+
Then I should see "An expectation of :foo was set on nil"
|
16
|
+
|
17
|
+
Scenario: allow
|
18
|
+
Given a file named "example_spec.rb" with:
|
19
|
+
"""
|
20
|
+
Rspec.configure {|c| c.mock_with :rspec}
|
21
|
+
describe "something" do
|
22
|
+
it "does something" do
|
23
|
+
allow_message_expectations_on_nil
|
24
|
+
nil.should_receive(:foo)
|
25
|
+
nil.foo
|
26
|
+
end
|
27
|
+
end
|
28
|
+
"""
|
29
|
+
When I run "rspec example_spec.rb"
|
30
|
+
Then I should not see "An expectation"
|
31
|
+
|
32
|
+
Scenario: allow in one example, but not on another
|
33
|
+
Given a file named "example_spec.rb" with:
|
34
|
+
"""
|
35
|
+
Rspec.configure {|c| c.mock_with :rspec}
|
36
|
+
describe "something" do
|
37
|
+
it "does something (foo)" do
|
38
|
+
allow_message_expectations_on_nil
|
39
|
+
nil.should_receive(:foo)
|
40
|
+
nil.foo
|
41
|
+
end
|
42
|
+
it "does something (bar)" do
|
43
|
+
nil.should_receive(:bar)
|
44
|
+
nil.bar
|
45
|
+
end
|
46
|
+
end
|
47
|
+
"""
|
48
|
+
When I run "rspec example_spec.rb"
|
49
|
+
Then I should see "An expectation of :bar"
|
50
|
+
And I should not see "An expectation of :foo"
|
data/lib/rspec/mocks.rb
CHANGED
@@ -68,13 +68,13 @@ module Rspec
|
|
68
68
|
#
|
69
69
|
# You can create a mock in any specification (or setup) using:
|
70
70
|
#
|
71
|
-
#
|
71
|
+
# double(name, options={})
|
72
72
|
#
|
73
73
|
# The optional +options+ argument is a +Hash+. Currently the only supported
|
74
74
|
# option is +:null_object+. Setting this to true instructs the mock to ignore
|
75
75
|
# any messages it hasn’t been told to expect – and quietly return itself. For example:
|
76
76
|
#
|
77
|
-
#
|
77
|
+
# double("person", :null_object => true)
|
78
78
|
#
|
79
79
|
# == Creating a Stub
|
80
80
|
#
|
@@ -93,7 +93,7 @@ module Rspec
|
|
93
93
|
# mock expectations to existing classes and objects:
|
94
94
|
#
|
95
95
|
# Factory.should_receive(:find).with(id).and_return(value)
|
96
|
-
# obj.stub
|
96
|
+
# obj.stub(:to_i).and_return(3)
|
97
97
|
# etc ...
|
98
98
|
#
|
99
99
|
# == Expecting Messages
|
@@ -168,12 +168,12 @@ module Rspec
|
|
168
168
|
# not support any qualifiers about the message received (i.e. you can't specify arguments
|
169
169
|
# or receive counts):
|
170
170
|
#
|
171
|
-
# my_mock.stub
|
172
|
-
# my_mock.stub
|
173
|
-
# my_mock.stub
|
174
|
-
# my_mock.stub
|
175
|
-
# my_mock.stub
|
176
|
-
# my_mock.stub
|
171
|
+
# my_mock.stub(:sym).and_return(value)
|
172
|
+
# my_mock.stub(:sym).and_return(value1, value2, value3)
|
173
|
+
# my_mock.stub(:sym).and_raise(error)
|
174
|
+
# my_mock.stub(:sym).and_throw(:sym)
|
175
|
+
# my_mock.stub(:sym).and_yield(values,to,yield)
|
176
|
+
# my_mock.stub(:sym).and_yield(values,to,yield).and_yield(some,other,values,this,time)
|
177
177
|
#
|
178
178
|
# == Arbitrary Handling
|
179
179
|
#
|
@@ -3,7 +3,8 @@ module Rspec
|
|
3
3
|
class ErrorGenerator
|
4
4
|
attr_writer :opts
|
5
5
|
|
6
|
-
def initialize(target, name)
|
6
|
+
def initialize(target, name, options={})
|
7
|
+
@declared_as = options[:__declared_as] || 'Mock'
|
7
8
|
@target = target
|
8
9
|
@name = name
|
9
10
|
end
|
@@ -18,12 +19,18 @@ module Rspec
|
|
18
19
|
|
19
20
|
def raise_unexpected_message_args_error(expectation, *args)
|
20
21
|
expected_args = format_args(*expectation.expected_args)
|
21
|
-
actual_args =
|
22
|
-
__raise "#{intro}
|
22
|
+
actual_args = format_args(*args)
|
23
|
+
__raise "#{intro} received #{expectation.sym.inspect} with unexpected arguments\n expected: #{expected_args}\n got: #{actual_args}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def raise_similar_message_args_error(expectation, *args)
|
27
|
+
expected_args = format_args(*expectation.expected_args)
|
28
|
+
actual_args = args.collect {|a| format_args(*a)}.join(", ")
|
29
|
+
__raise "#{intro} received #{expectation.sym.inspect} with unexpected arguments\n expected: #{expected_args}\n got: #{actual_args}"
|
23
30
|
end
|
24
31
|
|
25
32
|
def raise_expectation_error(sym, expected_received_count, actual_received_count, *args)
|
26
|
-
__raise "#{intro}
|
33
|
+
__raise "(#{intro}).#{sym}#{format_args(*args)}\n expected: #{count_message(expected_received_count)}\n received: #{count_message(actual_received_count)}"
|
27
34
|
end
|
28
35
|
|
29
36
|
def raise_out_of_order_error(sym)
|
@@ -45,7 +52,17 @@ module Rspec
|
|
45
52
|
private
|
46
53
|
|
47
54
|
def intro
|
48
|
-
|
55
|
+
if @name
|
56
|
+
"#{@declared_as} #{@name.inspect}"
|
57
|
+
elsif Mock === @target
|
58
|
+
@declared_as
|
59
|
+
elsif Class === @target
|
60
|
+
"<#{@target.inspect} (class)>"
|
61
|
+
elsif @target
|
62
|
+
@target
|
63
|
+
else
|
64
|
+
"nil"
|
65
|
+
end
|
49
66
|
end
|
50
67
|
|
51
68
|
def __raise(message)
|
@@ -71,11 +88,10 @@ module Rspec
|
|
71
88
|
end
|
72
89
|
|
73
90
|
def pretty_print(count)
|
74
|
-
|
75
|
-
return "twice" if count == 2
|
76
|
-
return "#{count} times"
|
91
|
+
"#{count} time#{count == 1 ? '' : 's'}"
|
77
92
|
end
|
78
93
|
|
79
94
|
end
|
80
95
|
end
|
81
96
|
end
|
97
|
+
|
@@ -244,7 +244,7 @@ module Rspec
|
|
244
244
|
if similar_messages.empty?
|
245
245
|
@error_generator.raise_expectation_error(@sym, @expected_received_count, @actual_received_count, *@args_expectation.args)
|
246
246
|
else
|
247
|
-
@error_generator.
|
247
|
+
@error_generator.raise_similar_message_args_error(self, *@similar_messages)
|
248
248
|
end
|
249
249
|
end
|
250
250
|
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module Rspec
|
2
|
+
module Mocks
|
3
|
+
class MethodDouble < Hash
|
4
|
+
attr_reader :method_name
|
5
|
+
|
6
|
+
def initialize(object, method_name, proxy)
|
7
|
+
@method_name = method_name
|
8
|
+
@object = object
|
9
|
+
@proxy = proxy
|
10
|
+
@stashed = false
|
11
|
+
store(:expectations, [])
|
12
|
+
store(:stubs, [])
|
13
|
+
end
|
14
|
+
|
15
|
+
def expectations
|
16
|
+
self[:expectations]
|
17
|
+
end
|
18
|
+
|
19
|
+
def stubs
|
20
|
+
self[:stubs]
|
21
|
+
end
|
22
|
+
|
23
|
+
def visibility
|
24
|
+
if Mock === @object
|
25
|
+
'public'
|
26
|
+
elsif object_singleton_class.private_method_defined?(@method_name)
|
27
|
+
'private'
|
28
|
+
elsif object_singleton_class.protected_method_defined?(@method_name)
|
29
|
+
'protected'
|
30
|
+
else
|
31
|
+
'public'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def object_singleton_class
|
36
|
+
class << @object; self; end
|
37
|
+
end
|
38
|
+
|
39
|
+
def obfuscate(method_name)
|
40
|
+
"obfuscated_by_rspec_mocks__#{method_name}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def stashed_method_name
|
44
|
+
obfuscate(method_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def object_responds_to?(method_name)
|
48
|
+
if @proxy.already_proxied_respond_to?
|
49
|
+
@object.__send__(obfuscate(:respond_to?), method_name)
|
50
|
+
elsif method_name == :respond_to?
|
51
|
+
@proxy.already_proxied_respond_to
|
52
|
+
else
|
53
|
+
@object.respond_to?(method_name, true)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def configure_method
|
58
|
+
$rspec_mocks.add(@object) if $rspec_mocks
|
59
|
+
warn_if_nil_class
|
60
|
+
stash_original_method
|
61
|
+
define_proxy_method
|
62
|
+
end
|
63
|
+
|
64
|
+
def stash_original_method
|
65
|
+
if object_responds_to?(@method_name)
|
66
|
+
stashed = stashed_method_name
|
67
|
+
orig = @method_name
|
68
|
+
object_singleton_class.class_eval do
|
69
|
+
alias_method(stashed, orig) if method_defined?(orig)
|
70
|
+
end
|
71
|
+
@stashed = true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def define_proxy_method
|
76
|
+
method_name = @method_name
|
77
|
+
visibility_for_method = "#{visibility} :#{method_name}"
|
78
|
+
object_singleton_class.class_eval(<<-EOF, __FILE__, __LINE__)
|
79
|
+
def #{method_name}(*args, &block)
|
80
|
+
__mock_proxy.message_received :#{method_name}, *args, &block
|
81
|
+
end
|
82
|
+
#{visibility_for_method}
|
83
|
+
EOF
|
84
|
+
end
|
85
|
+
|
86
|
+
def restore_original_method
|
87
|
+
if @stashed
|
88
|
+
method_name = @method_name
|
89
|
+
stashed_method_name = self.stashed_method_name
|
90
|
+
object_singleton_class.instance_eval do
|
91
|
+
remove_method method_name
|
92
|
+
if method_defined?(stashed_method_name)
|
93
|
+
alias_method method_name, stashed_method_name
|
94
|
+
remove_method stashed_method_name
|
95
|
+
end
|
96
|
+
end
|
97
|
+
@stashed = false
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def verify
|
102
|
+
expectations.each {|e| e.verify_messages_received}
|
103
|
+
end
|
104
|
+
|
105
|
+
def reset
|
106
|
+
reset_nil_expectations_warning
|
107
|
+
restore_original_method
|
108
|
+
clear
|
109
|
+
end
|
110
|
+
|
111
|
+
def clear
|
112
|
+
expectations.clear
|
113
|
+
stubs.clear
|
114
|
+
end
|
115
|
+
|
116
|
+
def add_expectation(error_generator, expectation_ordering, expected_from, opts, &block)
|
117
|
+
configure_method
|
118
|
+
expectation = if existing_stub = stubs.first
|
119
|
+
existing_stub.build_child(expected_from, block, 1, opts)
|
120
|
+
else
|
121
|
+
MessageExpectation.new(error_generator, expectation_ordering, expected_from, @method_name, block, 1, opts)
|
122
|
+
end
|
123
|
+
expectations << expectation
|
124
|
+
expectation
|
125
|
+
end
|
126
|
+
|
127
|
+
def add_negative_expectation(error_generator, expectation_ordering, expected_from, &implementation)
|
128
|
+
configure_method
|
129
|
+
expectation = NegativeMessageExpectation.new(error_generator, expectation_ordering, expected_from, @method_name, implementation)
|
130
|
+
expectations << expectation
|
131
|
+
expectation
|
132
|
+
end
|
133
|
+
|
134
|
+
def add_stub(error_generator, expectation_ordering, expected_from, opts={}, &implementation)
|
135
|
+
configure_method
|
136
|
+
stub = MessageExpectation.new(error_generator, expectation_ordering, expected_from, @method_name, nil, :any, opts, &implementation)
|
137
|
+
stubs << stub
|
138
|
+
stub
|
139
|
+
end
|
140
|
+
|
141
|
+
def proxy_for_nil_class?
|
142
|
+
@object.nil?
|
143
|
+
end
|
144
|
+
|
145
|
+
def warn_if_nil_class
|
146
|
+
if proxy_for_nil_class? & Rspec::Mocks::Proxy.warn_about_expectations_on_nil
|
147
|
+
Kernel.warn("An expectation of :#{@method_name} was set on nil. Called from #{caller[4]}. Use allow_message_expectations_on_nil to disable warnings.")
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def reset_nil_expectations_warning
|
152
|
+
Rspec::Mocks::Proxy.warn_about_expectations_on_nil = true if proxy_for_nil_class?
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
data/lib/rspec/mocks/methods.rb
CHANGED
@@ -9,7 +9,7 @@ module Rspec
|
|
9
9
|
__mock_proxy.add_negative_message_expectation(caller(1)[0], sym.to_sym, &block)
|
10
10
|
end
|
11
11
|
|
12
|
-
def stub
|
12
|
+
def stub(sym_or_hash, opts={}, &block)
|
13
13
|
if Hash === sym_or_hash
|
14
14
|
sym_or_hash.each {|method, value| stub!(method).and_return value }
|
15
15
|
else
|
@@ -17,7 +17,7 @@ module Rspec
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
alias_method :stub
|
20
|
+
alias_method :stub!, :stub
|
21
21
|
|
22
22
|
def stub_chain(*methods)
|
23
23
|
if methods.length > 1
|
data/lib/rspec/mocks/mock.rb
CHANGED
@@ -7,14 +7,14 @@ module Rspec
|
|
7
7
|
# only) == Options:
|
8
8
|
# * <tt>:null_object</tt> - if true, the mock object acts as a forgiving
|
9
9
|
# null object allowing any message to be sent to it.
|
10
|
-
def initialize(name=
|
10
|
+
def initialize(name=nil, stubs_and_options={})
|
11
11
|
if name.is_a?(Hash) && stubs_and_options.empty?
|
12
12
|
stubs_and_options = name
|
13
|
-
|
13
|
+
@name = nil
|
14
14
|
else
|
15
15
|
@name = name
|
16
16
|
end
|
17
|
-
@options =
|
17
|
+
@options = extract_options(stubs_and_options)
|
18
18
|
assign_stubs(stubs_and_options)
|
19
19
|
end
|
20
20
|
|
@@ -46,8 +46,19 @@ module Rspec
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
def
|
50
|
-
options
|
49
|
+
def extract_options(stubs_and_options)
|
50
|
+
options = {}
|
51
|
+
extract_option(stubs_and_options, options, :null_object)
|
52
|
+
extract_option(stubs_and_options, options, :__declared_as, 'Mock')
|
53
|
+
options
|
54
|
+
end
|
55
|
+
|
56
|
+
def extract_option(source, target, key, default=nil)
|
57
|
+
if source[key]
|
58
|
+
target[key] = source.delete(key)
|
59
|
+
elsif default
|
60
|
+
target[key] = default
|
61
|
+
end
|
51
62
|
end
|
52
63
|
|
53
64
|
def assign_stubs(stubs)
|
@@ -55,11 +66,7 @@ module Rspec
|
|
55
66
|
stub!(message).and_return(response)
|
56
67
|
end
|
57
68
|
end
|
58
|
-
|
59
|
-
def build_name_from_options(options)
|
60
|
-
vals = options.inject([]) {|coll, pair| coll << "#{pair.first}: #{pair.last.inspect}"}
|
61
|
-
@name = '{' + vals.join(', ') + '}'
|
62
|
-
end
|
63
69
|
end
|
64
70
|
end
|
65
71
|
end
|
72
|
+
|