rspec-mocks 2.99.4 → 3.0.0.beta1
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.
- checksums.yaml +14 -6
- checksums.yaml.gz.sig +2 -0
- data.tar.gz.sig +1 -0
- data/Changelog.md +89 -105
- data/License.txt +1 -0
- data/README.md +77 -57
- data/features/argument_matchers/explicit.feature +5 -5
- data/features/argument_matchers/general_matchers.feature +10 -10
- data/features/argument_matchers/type_matchers.feature +3 -3
- data/features/message_expectations/allow_any_instance_of.feature +1 -1
- data/features/message_expectations/any_instance.feature +27 -5
- data/features/message_expectations/call_original.feature +2 -2
- data/features/message_expectations/expect_message_using_expect.feature +2 -2
- data/features/message_expectations/expect_message_using_should_receive.feature +2 -2
- data/features/message_expectations/receive_counts.feature +7 -7
- data/features/message_expectations/warn_when_expectation_is_set_on_nil.feature +3 -3
- data/features/method_stubs/README.md +3 -0
- data/features/method_stubs/any_instance.feature +11 -11
- data/features/method_stubs/as_null_object.feature +4 -4
- data/features/method_stubs/simple_return_value_with_stub.feature +7 -7
- data/features/method_stubs/stub_chain.feature +3 -3
- data/features/method_stubs/stub_implementation.feature +2 -2
- data/features/method_stubs/to_ary.feature +2 -2
- data/features/mutating_constants/hiding_defined_constant.feature +2 -2
- data/features/mutating_constants/stub_defined_constant.feature +5 -5
- data/features/mutating_constants/stub_undefined_constant.feature +6 -6
- data/features/outside_rspec/configuration.feature +0 -2
- data/features/outside_rspec/standalone.feature +1 -1
- data/features/spies/spy_partial_mock_method.feature +2 -2
- data/features/spies/spy_pure_mock_method.feature +5 -5
- data/features/spies/spy_unstubbed_method.feature +1 -1
- data/features/support/env.rb +10 -1
- data/features/test_frameworks/test_unit.feature +1 -1
- data/features/verifying_doubles/class_doubles.feature +88 -0
- data/features/verifying_doubles/dynamic_classes.feature +72 -0
- data/features/verifying_doubles/introduction.feature +85 -0
- data/features/verifying_doubles/object_doubles.feature +65 -0
- data/features/verifying_doubles/partial_doubles.feature +34 -0
- data/lib/rspec/mocks.rb +8 -34
- data/lib/rspec/mocks/any_instance/chain.rb +4 -34
- data/lib/rspec/mocks/any_instance/expectation_chain.rb +14 -4
- data/lib/rspec/mocks/any_instance/message_chains.rb +27 -12
- data/lib/rspec/mocks/any_instance/recorder.rb +23 -31
- data/lib/rspec/mocks/any_instance/stub_chain.rb +9 -4
- data/lib/rspec/mocks/argument_list_matcher.rb +8 -1
- data/lib/rspec/mocks/argument_matchers.rb +26 -12
- data/lib/rspec/mocks/arity_calculator.rb +66 -0
- data/lib/rspec/mocks/configuration.rb +42 -14
- data/lib/rspec/mocks/error_generator.rb +34 -10
- data/lib/rspec/mocks/example_methods.rb +64 -19
- data/lib/rspec/mocks/extensions/marshal.rb +0 -15
- data/lib/rspec/mocks/framework.rb +4 -4
- data/lib/rspec/mocks/instance_method_stasher.rb +80 -62
- data/lib/rspec/mocks/matchers/have_received.rb +18 -14
- data/lib/rspec/mocks/matchers/receive.rb +29 -7
- data/lib/rspec/mocks/matchers/receive_messages.rb +72 -0
- data/lib/rspec/mocks/message_expectation.rb +95 -148
- data/lib/rspec/mocks/method_double.rb +77 -139
- data/lib/rspec/mocks/method_reference.rb +95 -0
- data/lib/rspec/mocks/mock.rb +1 -1
- data/lib/rspec/mocks/mutate_const.rb +12 -9
- data/lib/rspec/mocks/object_reference.rb +90 -0
- data/lib/rspec/mocks/order_group.rb +49 -7
- data/lib/rspec/mocks/proxy.rb +72 -33
- data/lib/rspec/mocks/proxy_for_nil.rb +2 -2
- data/lib/rspec/mocks/space.rb +13 -18
- data/lib/rspec/mocks/stub_chain.rb +2 -2
- data/lib/rspec/mocks/syntax.rb +61 -36
- data/lib/rspec/mocks/targets.rb +40 -19
- data/lib/rspec/mocks/test_double.rb +12 -56
- data/lib/rspec/mocks/verifying_double.rb +77 -0
- data/lib/rspec/mocks/verifying_message_expecation.rb +60 -0
- data/lib/rspec/mocks/verifying_proxy.rb +151 -0
- data/lib/rspec/mocks/version.rb +1 -1
- data/spec/rspec/mocks/and_call_original_spec.rb +34 -30
- data/spec/rspec/mocks/and_yield_spec.rb +2 -2
- data/spec/rspec/mocks/any_instance/message_chains_spec.rb +1 -1
- data/spec/rspec/mocks/any_instance_spec.rb +53 -260
- data/spec/rspec/mocks/argument_expectation_spec.rb +4 -4
- data/spec/rspec/mocks/arity_calculator_spec.rb +95 -0
- data/spec/rspec/mocks/array_including_matcher_spec.rb +41 -0
- data/spec/rspec/mocks/at_least_spec.rb +4 -32
- data/spec/rspec/mocks/block_return_value_spec.rb +4 -135
- data/spec/rspec/mocks/combining_implementation_instructions_spec.rb +10 -11
- data/spec/rspec/mocks/configuration_spec.rb +79 -0
- data/spec/rspec/mocks/double_spec.rb +10 -78
- data/spec/rspec/mocks/extensions/marshal_spec.rb +0 -8
- data/spec/rspec/mocks/failing_argument_matchers_spec.rb +49 -4
- data/spec/rspec/mocks/instance_method_stasher_spec.rb +20 -3
- data/spec/rspec/mocks/matchers/have_received_spec.rb +74 -0
- data/spec/rspec/mocks/matchers/receive_messages_spec.rb +140 -0
- data/spec/rspec/mocks/matchers/receive_spec.rb +82 -42
- data/spec/rspec/mocks/methods_spec.rb +1 -1
- data/spec/rspec/mocks/{bug_report_830_spec.rb → mock_expectation_error_spec.rb} +4 -3
- data/spec/rspec/mocks/mock_ordering_spec.rb +11 -0
- data/spec/rspec/mocks/mock_space_spec.rb +10 -1
- data/spec/rspec/mocks/mock_spec.rb +26 -82
- data/spec/rspec/mocks/multiple_return_value_spec.rb +1 -1
- data/spec/rspec/mocks/mutate_const_spec.rb +18 -5
- data/spec/rspec/mocks/null_object_mock_spec.rb +6 -4
- data/spec/rspec/mocks/options_hash_spec.rb +3 -3
- data/spec/rspec/mocks/order_group_spec.rb +27 -0
- data/spec/rspec/mocks/partial_mock_spec.rb +101 -1
- data/spec/rspec/mocks/passing_argument_matchers_spec.rb +3 -20
- data/spec/rspec/mocks/record_messages_spec.rb +4 -4
- data/spec/rspec/mocks/serialization_spec.rb +4 -6
- data/spec/rspec/mocks/space_spec.rb +3 -3
- data/spec/rspec/mocks/stub_chain_spec.rb +0 -12
- data/spec/rspec/mocks/stub_spec.rb +23 -44
- data/spec/rspec/mocks/test_double_spec.rb +3 -22
- data/spec/rspec/mocks/verifying_double_spec.rb +327 -0
- data/spec/rspec/mocks/verifying_message_expecation_spec.rb +68 -0
- data/spec/rspec/mocks_spec.rb +16 -39
- data/spec/spec_helper.rb +29 -18
- metadata +131 -86
- metadata.gz.sig +1 -0
- data/features/message_expectations/expect_any_instance_of.feature +0 -27
- data/lib/rspec/mocks/caller_filter.rb +0 -60
- data/lib/rspec/mocks/deprecation.rb +0 -26
- data/lib/rspec/mocks/extensions/instance_exec.rb +0 -34
- data/lib/rspec/mocks/extensions/proc.rb +0 -63
- data/lib/spec/mocks.rb +0 -4
- data/spec/rspec/mocks/and_return_spec.rb +0 -17
- data/spec/rspec/mocks/any_number_of_times_spec.rb +0 -36
- data/spec/rspec/mocks/before_all_spec.rb +0 -74
- data/spec/rspec/mocks/bug_report_10260_spec.rb +0 -8
- data/spec/rspec/mocks/bug_report_10263_spec.rb +0 -27
- data/spec/rspec/mocks/bug_report_11545_spec.rb +0 -32
- data/spec/rspec/mocks/bug_report_496_spec.rb +0 -17
- data/spec/rspec/mocks/bug_report_600_spec.rb +0 -22
- data/spec/rspec/mocks/bug_report_7611_spec.rb +0 -16
- data/spec/rspec/mocks/bug_report_8165_spec.rb +0 -31
- data/spec/rspec/mocks/bug_report_957_spec.rb +0 -22
@@ -28,21 +28,21 @@ Feature: stub a chain of methods
|
|
28
28
|
context "given symbols representing methods" do
|
29
29
|
it "returns the correct value" do
|
30
30
|
subject.stub_chain(:one, :two, :three).and_return(:four)
|
31
|
-
subject.one.two.three.
|
31
|
+
expect(subject.one.two.three).to eq(:four)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
context "given a hash at the end" do
|
36
36
|
it "returns the correct value" do
|
37
37
|
subject.stub_chain(:one, :two, :three => :four)
|
38
|
-
subject.one.two.three.
|
38
|
+
expect(subject.one.two.three).to eq(:four)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
context "given a string of methods separated by dots" do
|
43
43
|
it "returns the correct value" do
|
44
44
|
subject.stub_chain("one.two.three").and_return(:four)
|
45
|
-
subject.one.two.three.
|
45
|
+
expect(subject.one.two.three).to eq(:four)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -39,8 +39,8 @@ Feature: stub with substitute implementation
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
object.foo(:this).
|
43
|
-
object.foo(:that).
|
42
|
+
expect(object.foo(:this)).to eq("got this")
|
43
|
+
expect(object.foo(:that)).to eq("got that")
|
44
44
|
end
|
45
45
|
end
|
46
46
|
"""
|
@@ -19,12 +19,12 @@ Feature: double handling to_ary
|
|
19
19
|
shared_examples "to_ary" do
|
20
20
|
it "can be overridden with a stub" do
|
21
21
|
obj.stub(:to_ary) { :non_nil_value }
|
22
|
-
obj.to_ary.
|
22
|
+
expect(obj.to_ary).to be(:non_nil_value)
|
23
23
|
end
|
24
24
|
|
25
25
|
it "supports Array#flatten" do
|
26
26
|
obj = double('foo')
|
27
|
-
[obj].flatten.
|
27
|
+
expect([obj].flatten).to eq([obj])
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -14,7 +14,7 @@ Feature: Hide Defined Constant
|
|
14
14
|
end
|
15
15
|
|
16
16
|
it "restores the hidden constant when the example completes" do
|
17
|
-
FOO.
|
17
|
+
expect(FOO).to eq(7)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
"""
|
@@ -38,7 +38,7 @@ Feature: Hide Defined Constant
|
|
38
38
|
end
|
39
39
|
|
40
40
|
it "restores the hidden constant when the example completes" do
|
41
|
-
MyGem::SomeClass::FOO.
|
41
|
+
expect(MyGem::SomeClass::FOO).to eq(7)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
@@ -12,11 +12,11 @@ Feature: Stub Defined Constant
|
|
12
12
|
describe "stubbing FOO" do
|
13
13
|
it "can stub FOO with a different value" do
|
14
14
|
stub_const("FOO", 5)
|
15
|
-
FOO.
|
15
|
+
expect(FOO).to eq(5)
|
16
16
|
end
|
17
17
|
|
18
18
|
it "restores the stubbed constant when the example completes" do
|
19
|
-
FOO.
|
19
|
+
expect(FOO).to eq(7)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
"""
|
@@ -36,7 +36,7 @@ Feature: Stub Defined Constant
|
|
36
36
|
describe SomeClass do
|
37
37
|
it "stubs the nested constant when it is fully qualified" do
|
38
38
|
stub_const("MyGem::SomeClass::FOO", 5)
|
39
|
-
SomeClass::FOO.
|
39
|
+
expect(SomeClass::FOO).to eq(5)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -64,12 +64,12 @@ Feature: Stub Defined Constant
|
|
64
64
|
|
65
65
|
it "transfers nested constants when using :transfer_nested_constants => true" do
|
66
66
|
stub_const("MyGem::SomeClass", fake_class, :transfer_nested_constants => true)
|
67
|
-
SomeClass::FOO.
|
67
|
+
expect(SomeClass::FOO).to eq(7)
|
68
68
|
end
|
69
69
|
|
70
70
|
it "can specify a list of nested constants to transfer" do
|
71
71
|
stub_const("MyGem::SomeClass", fake_class, :transfer_nested_constants => [:FOO])
|
72
|
-
SomeClass::FOO.
|
72
|
+
expect(SomeClass::FOO).to eq(7)
|
73
73
|
end
|
74
74
|
end
|
75
75
|
end
|
@@ -11,7 +11,7 @@ Feature: Stub Undefined Constant
|
|
11
11
|
describe "stubbing FOO" do
|
12
12
|
it "can stub undefined constant FOO" do
|
13
13
|
stub_const("FOO", 5)
|
14
|
-
FOO.
|
14
|
+
expect(FOO).to eq(5)
|
15
15
|
end
|
16
16
|
|
17
17
|
it "undefines the constant when the example completes" do
|
@@ -33,15 +33,15 @@ Feature: Stub Undefined Constant
|
|
33
33
|
module MyGem
|
34
34
|
describe SomeClass do
|
35
35
|
it "can stub an arbitrarily deep constant that is undefined" do
|
36
|
-
defined?(SomeClass::A).
|
36
|
+
expect(defined?(SomeClass::A)).to be_falsey
|
37
37
|
stub_const("MyGem::SomeClass::A::B::C", 3)
|
38
|
-
SomeClass::A::B::C.
|
39
|
-
SomeClass::A.
|
38
|
+
expect(SomeClass::A::B::C).to eq(3)
|
39
|
+
expect(SomeClass::A).to be_a(Module)
|
40
40
|
end
|
41
41
|
|
42
42
|
it 'undefines the intermediary constants that were dynamically created' do
|
43
|
-
defined?(SomeClass).
|
44
|
-
defined?(SomeClass::A).
|
43
|
+
expect(defined?(SomeClass)).to be_truthy
|
44
|
+
expect(defined?(SomeClass::A)).to be_falsey
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
@@ -11,7 +11,7 @@ Feature: Spy on a stubbed method on a partial mock
|
|
11
11
|
invitation = Object.new
|
12
12
|
invitation.stub(:deliver => true)
|
13
13
|
invitation.deliver
|
14
|
-
invitation.
|
14
|
+
expect(invitation).to have_received(:deliver)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
"""
|
@@ -25,7 +25,7 @@ Feature: Spy on a stubbed method on a partial mock
|
|
25
25
|
it "fails when the expectation is not met" do
|
26
26
|
invitation = Object.new
|
27
27
|
invitation.stub(:deliver => true)
|
28
|
-
invitation.
|
28
|
+
expect(invitation).to have_received(:deliver)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
"""
|
@@ -10,7 +10,7 @@ Feature: Spy on a stubbed method on a pure mock
|
|
10
10
|
it "passes when the expectation is met" do
|
11
11
|
invitation = double('invitation', :deliver => true)
|
12
12
|
invitation.deliver
|
13
|
-
invitation.
|
13
|
+
expect(invitation).to have_received(:deliver)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
"""
|
@@ -24,7 +24,7 @@ Feature: Spy on a stubbed method on a pure mock
|
|
24
24
|
it "passes when the expectation is met" do
|
25
25
|
invitation = double('invitation', :deliver => true)
|
26
26
|
2.times { invitation.deliver(:expected, :arguments) }
|
27
|
-
invitation.
|
27
|
+
expect(invitation).to have_received(:deliver).
|
28
28
|
with(:expected, :arguments).
|
29
29
|
twice
|
30
30
|
end
|
@@ -39,7 +39,7 @@ Feature: Spy on a stubbed method on a pure mock
|
|
39
39
|
describe "have_received" do
|
40
40
|
it "fails when the expectation is not met" do
|
41
41
|
invitation = double('invitation', :deliver => true)
|
42
|
-
invitation.
|
42
|
+
expect(invitation).to have_received(:deliver)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
"""
|
@@ -54,7 +54,7 @@ Feature: Spy on a stubbed method on a pure mock
|
|
54
54
|
it "fails when the arguments are different" do
|
55
55
|
invitation = double('invitation', :deliver => true)
|
56
56
|
invitation.deliver(:unexpected)
|
57
|
-
invitation.
|
57
|
+
expect(invitation).to have_received(:deliver).with(:expected, :arguments)
|
58
58
|
end
|
59
59
|
end
|
60
60
|
"""
|
@@ -66,7 +66,7 @@ Feature: Spy on a stubbed method on a pure mock
|
|
66
66
|
Given a file named "spy_message_spec.rb" with:
|
67
67
|
"""ruby
|
68
68
|
describe "have_received" do
|
69
|
-
|
69
|
+
subject(:invitation) { double('invitation', :deliver => true) }
|
70
70
|
before { invitation.deliver }
|
71
71
|
|
72
72
|
it { should have_received(:deliver) }
|
data/features/support/env.rb
CHANGED
@@ -2,7 +2,11 @@ require 'aruba/cucumber'
|
|
2
2
|
require 'rspec/expectations'
|
3
3
|
|
4
4
|
Before do
|
5
|
-
RUBY_PLATFORM =~ /java/ ?
|
5
|
+
if RUBY_PLATFORM =~ /java/ || defined?(Rubinius)
|
6
|
+
@aruba_timeout_seconds = 60
|
7
|
+
else
|
8
|
+
@aruba_timeout_seconds = 5
|
9
|
+
end
|
6
10
|
end
|
7
11
|
|
8
12
|
Aruba.configure do |config|
|
@@ -11,3 +15,8 @@ Aruba.configure do |config|
|
|
11
15
|
end
|
12
16
|
end if RUBY_PLATFORM == 'java'
|
13
17
|
|
18
|
+
Aruba.configure do |config|
|
19
|
+
config.before_cmd do |cmd|
|
20
|
+
set_env('RBXOPT', "-Xint=true #{ENV['RBXOPT']}") # disable JIT since these processes are so short lived
|
21
|
+
end
|
22
|
+
end if defined?(Rubinius)
|
@@ -40,4 +40,4 @@ Feature: Test::Unit integration
|
|
40
40
|
When I run `ruby rspec_mocks_test.rb`
|
41
41
|
Then the output should contain "3 tests, 0 assertions, 0 failures, 1 errors" or "3 tests, 0 assertions, 1 failures, 0 errors"
|
42
42
|
And the output should contain "expected: 0 times with any arguments"
|
43
|
-
And the output should contain "old_message is deprecated
|
43
|
+
And the output should contain "old_message is deprecated"
|
@@ -0,0 +1,88 @@
|
|
1
|
+
Feature: Using a class double
|
2
|
+
|
3
|
+
`class_double` is provided as a complement to `instance_double`, with the
|
4
|
+
difference that it verifies class methods on the given class rather than
|
5
|
+
instance methods.
|
6
|
+
|
7
|
+
In addition, it also provides a convenience method `as_stubbed_const` to
|
8
|
+
replace concrete classes with the defined double. See [mutating
|
9
|
+
constants](../mutating-constants) for more details.
|
10
|
+
|
11
|
+
Note: `class_double` can be used for modules as well. We chose to stick with
|
12
|
+
the `class_double` terminology because the methods a `class_double` verifies
|
13
|
+
against are commonly called "class methods", not "module methods", even when
|
14
|
+
working with a module.
|
15
|
+
|
16
|
+
Background:
|
17
|
+
Given a file named "lib/user.rb" with:
|
18
|
+
"""ruby
|
19
|
+
class User
|
20
|
+
def suspend!
|
21
|
+
ConsoleNotifier.notify("suspended as")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
"""
|
25
|
+
|
26
|
+
Given a file named "lib/console_notifier.rb" with:
|
27
|
+
"""ruby
|
28
|
+
class ConsoleNotifier
|
29
|
+
MAX_WIDTH = 80
|
30
|
+
|
31
|
+
def self.notify(message)
|
32
|
+
puts message
|
33
|
+
end
|
34
|
+
end
|
35
|
+
"""
|
36
|
+
|
37
|
+
Given a file named "spec/user_spec.rb" with:
|
38
|
+
"""ruby
|
39
|
+
require 'user'
|
40
|
+
require 'console_notifier'
|
41
|
+
|
42
|
+
describe User, '#suspend!' do
|
43
|
+
it 'notifies the console' do
|
44
|
+
notifier = class_double("ConsoleNotifier").
|
45
|
+
as_stubbed_const(:transfer_nested_constants => true)
|
46
|
+
|
47
|
+
expect(notifier).to receive(:notify).with("suspended as")
|
48
|
+
expect(ConsoleNotifier::MAX_WIDTH).to eq(80)
|
49
|
+
|
50
|
+
user = User.new
|
51
|
+
user.suspend!
|
52
|
+
end
|
53
|
+
end
|
54
|
+
"""
|
55
|
+
|
56
|
+
Scenario: replacing existing constants
|
57
|
+
When I run `rspec spec/user_spec.rb`
|
58
|
+
Then the examples should all pass
|
59
|
+
|
60
|
+
Scenario: renaming `ConsoleNotifier.notify` to `send_notification`
|
61
|
+
Given a file named "lib/console_notifier.rb" with:
|
62
|
+
"""ruby
|
63
|
+
class ConsoleNotifier
|
64
|
+
MAX_WIDTH = 80
|
65
|
+
|
66
|
+
def self.send_notification(message)
|
67
|
+
puts message
|
68
|
+
end
|
69
|
+
end
|
70
|
+
"""
|
71
|
+
When I run `rspec spec/user_spec.rb`
|
72
|
+
Then the output should contain "1 example, 1 failure"
|
73
|
+
And the output should contain "ConsoleNotifier does not implement:"
|
74
|
+
|
75
|
+
Scenario: adding `color` as a second argument to `ConsoleNotifier.notify`
|
76
|
+
Given a file named "lib/console_notifier.rb" with:
|
77
|
+
"""ruby
|
78
|
+
class ConsoleNotifier
|
79
|
+
MAX_WIDTH = 80
|
80
|
+
|
81
|
+
def self.notify(message, color)
|
82
|
+
puts color + message
|
83
|
+
end
|
84
|
+
end
|
85
|
+
"""
|
86
|
+
When I run `rspec spec/user_spec.rb`
|
87
|
+
Then the output should contain "1 example, 1 failure"
|
88
|
+
And the output should contain "Wrong number of arguments."
|
@@ -0,0 +1,72 @@
|
|
1
|
+
Feature: Dynamic classes
|
2
|
+
|
3
|
+
Verifying instance doubles do not support methods which the class reports to
|
4
|
+
not exist since an actual instance of the class would be required to verify
|
5
|
+
against. This is commonly the case when `method_missing` is used.
|
6
|
+
`ActiveRecord` does this to define methods from database columns. If the
|
7
|
+
object has already been loaded you may consider using an `object_double`, but
|
8
|
+
that cannot work if you are testing in isolation.
|
9
|
+
|
10
|
+
These types of methods are supported at class level, since `respond_to?` can
|
11
|
+
be queried directly on the class.
|
12
|
+
|
13
|
+
|
14
|
+
Background:
|
15
|
+
Given a file named "lib/fake_active_record.rb" with:
|
16
|
+
"""ruby
|
17
|
+
class FakeActiveRecord
|
18
|
+
COLUMNS = %w[name email]
|
19
|
+
|
20
|
+
def respond_to_missing?(method_name)
|
21
|
+
COLUMNS.include?(method_name.to_s) || super
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_missing(method_name, *args)
|
25
|
+
if respond_to?(method_name)
|
26
|
+
instance_variable_get("@#{method_name}")
|
27
|
+
else
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
"""
|
33
|
+
|
34
|
+
Given a file named "spec/user_spec.rb" with:
|
35
|
+
"""ruby
|
36
|
+
require 'user'
|
37
|
+
|
38
|
+
describe User do
|
39
|
+
it 'can be doubled' do
|
40
|
+
instance_double("User", :name => "Don")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
"""
|
44
|
+
|
45
|
+
Scenario: fails with method missing
|
46
|
+
|
47
|
+
Given a file named "lib/user.rb" with:
|
48
|
+
"""ruby
|
49
|
+
require 'fake_active_record'
|
50
|
+
|
51
|
+
class User < FakeActiveRecord
|
52
|
+
end
|
53
|
+
"""
|
54
|
+
|
55
|
+
When I run `rspec spec/user_spec.rb`
|
56
|
+
Then the output should contain "1 example, 1 failure"
|
57
|
+
|
58
|
+
Scenario: workaround with explict definitions
|
59
|
+
|
60
|
+
Given a file named "lib/user.rb" with:
|
61
|
+
"""ruby
|
62
|
+
require 'fake_active_record'
|
63
|
+
|
64
|
+
class User < FakeActiveRecord
|
65
|
+
def name; super end
|
66
|
+
def email; super end
|
67
|
+
end
|
68
|
+
"""
|
69
|
+
|
70
|
+
When I run `rspec spec/user_spec.rb`
|
71
|
+
Then the examples should all pass
|
72
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
Feature: Verifying doubles
|
2
|
+
|
3
|
+
Verifying doubles are a stricter alternative to normal doubles that provide
|
4
|
+
guarantees about what is being verified. When using verifying doubles, RSpec
|
5
|
+
will check that the methods being stubbed are actually present on the
|
6
|
+
underlying object if it is available. Prefer using veryifing doubles over
|
7
|
+
normal doubles.
|
8
|
+
|
9
|
+
No checking will happen if the constant name is not defined, but when run
|
10
|
+
with the constant present (either as a full spec run or by explicitly
|
11
|
+
preloading collaborators) a failure will be triggered if an invalid method is
|
12
|
+
being stubbed.
|
13
|
+
|
14
|
+
This dual approach allows you to move very quickly and test components in
|
15
|
+
isolation, while giving you confidence that your doubles are not a complete
|
16
|
+
fiction. Testing in isolation is optional but recommend for classes that do
|
17
|
+
not depend on third-party components.
|
18
|
+
|
19
|
+
Background:
|
20
|
+
Given a file named "app/models/user.rb" with:
|
21
|
+
"""ruby
|
22
|
+
class User < Struct.new(:notifier)
|
23
|
+
def suspend!
|
24
|
+
notifier.notify("suspended as")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
"""
|
28
|
+
|
29
|
+
Given a file named "app/models/console_notifier.rb" with:
|
30
|
+
"""ruby
|
31
|
+
class ConsoleNotifier
|
32
|
+
# notify is not defined yet.
|
33
|
+
end
|
34
|
+
"""
|
35
|
+
|
36
|
+
Given a file named "spec/unit_helper.rb" with:
|
37
|
+
"""ruby
|
38
|
+
$LOAD_PATH.unshift("app/models")
|
39
|
+
"""
|
40
|
+
|
41
|
+
Given a file named "spec/spec_helper.rb" with:
|
42
|
+
"""ruby
|
43
|
+
require 'unit_helper'
|
44
|
+
|
45
|
+
require 'user'
|
46
|
+
require 'console_notifier'
|
47
|
+
|
48
|
+
RSpec.configure do |config|
|
49
|
+
config.mock_with :rspec do |mocks|
|
50
|
+
|
51
|
+
# This option should be set when all dependencies are being loaded
|
52
|
+
# before a spec run, as is the case in a typical spec helper. It will
|
53
|
+
# cause any verifying double instantiation for a class that does not
|
54
|
+
# exist to raise, protecting against incorrectly spelt names.
|
55
|
+
mocks.verify_doubled_constant_names = true
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
"""
|
60
|
+
|
61
|
+
Given a file named "spec/unit/user_spec.rb" with:
|
62
|
+
"""ruby
|
63
|
+
require 'unit_helper'
|
64
|
+
|
65
|
+
require 'user'
|
66
|
+
|
67
|
+
describe User, '#suspend!' do
|
68
|
+
it 'notifies the console' do
|
69
|
+
notifier = instance_double("ConsoleNotifier")
|
70
|
+
|
71
|
+
expect(notifier).to receive(:notify).with("suspended as")
|
72
|
+
|
73
|
+
user = User.new(notifier)
|
74
|
+
user.suspend!
|
75
|
+
end
|
76
|
+
end
|
77
|
+
"""
|
78
|
+
|
79
|
+
Scenario: spec passes in isolation
|
80
|
+
When I run `rspec spec/unit/user_spec.rb`
|
81
|
+
Then the examples should all pass
|
82
|
+
|
83
|
+
Scenario: spec fails with dependencies loaded
|
84
|
+
When I run `rspec -r./spec/spec_helper spec/unit/user_spec.rb`
|
85
|
+
Then the output should contain "1 example, 1 failure"
|