1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
require 'support/doubled_classes'
module RSpec
module Mocks
RSpec.describe 'An object double' do
let(:loaded_instance) { LoadedClass.new(1, 2) }
it 'can replace an unloaded constant' do
o = object_double("LoadedClass::NOINSTANCE").as_stubbed_const
expect(LoadedClass::NOINSTANCE).to eq(o)
expect(o).to receive(:undefined_instance_method)
o.undefined_instance_method
end
it 'can replace a constant by name and verify instance methods' do
o = object_double("LoadedClass::INSTANCE").as_stubbed_const
expect(LoadedClass::INSTANCE).to eq(o)
prevents { expect(o).to receive(:undefined_instance_method) }
prevents { expect(o).to receive(:defined_class_method) }
prevents { o.defined_instance_method }
expect(o).to receive(:defined_instance_method)
o.defined_instance_method
expect(o).to receive(:defined_private_method)
o.send :defined_private_method
end
it 'can create a double that matches the interface of any arbitrary object' do
o = object_double(loaded_instance)
prevents { expect(o).to receive(:undefined_instance_method) }
prevents { expect(o).to receive(:defined_class_method) }
prevents { o.defined_instance_method }
expect(o).to receive(:defined_instance_method)
o.defined_instance_method
expect(o).to receive(:defined_private_method)
o.send :defined_private_method
end
it 'does not allow transferring constants to an object' do
expect {
object_double("LoadedClass::INSTANCE").
as_stubbed_const(:transfer_nested_constants => true)
}.to raise_error(/Cannot transfer nested constants/)
end
it 'does not allow as_stubbed_constant for real objects' do
expect {
object_double(loaded_instance).as_stubbed_const
}.to raise_error(/Can not perform constant replacement with an anonymous object/)
end
it 'is not a module' do
expect(object_double("LoadedClass::INSTANCE")).to_not be_a(Module)
end
it 'validates `with` args against the method signature when stubbing a method' do
dbl = object_double(loaded_instance)
prevents(/Wrong number of arguments. Expected 2, got 3./) {
allow(dbl).to receive(:instance_method_with_two_args).with(3, :foo, :args)
}
end
context "when a loaded object constant has previously been stubbed with an object" do
before { stub_const("LoadedClass::INSTANCE", Object.new) }
it "uses the original object to verify against for `object_double('ConstName')`" do
o = object_double("LoadedClass::INSTANCE")
allow(o).to receive(:defined_instance_method)
prevents { allow(o).to receive(:undefined_meth) }
end
it "uses the stubbed const value to verify against for `object_double(ConstName)`, " \
"which probably isn't what the user wants, but there's nothing else we can do since " \
"we can't get the constant name from the given object and thus cannot interrogate " \
"our stubbed const registry to see it has been stubbed" do
o = object_double(LoadedClass::INSTANCE)
prevents { allow(o).to receive(:defined_instance_method) }
end
end
context "when a loaded object constant has previously been stubbed with a class" do
before { stub_const("LoadedClass::INSTANCE", Class.new) }
it "uses the original object to verify against for `object_double('ConstName')`" do
o = object_double("LoadedClass::INSTANCE")
allow(o).to receive(:defined_instance_method)
prevents { allow(o).to receive(:undefined_meth) }
end
it "uses the original object to verify against for `object_double(ConstName)`" do
o = object_double(LoadedClass::INSTANCE)
allow(o).to receive(:defined_instance_method)
prevents { allow(o).to receive(:undefined_meth) }
end
end
context "when an unloaded object constant has previously been stubbed with an object" do
before { stub_const("LoadedClass::NOINSTANCE", LoadedClass::INSTANCE) }
it "treats it as being unloaded for `object_double('ConstName')`" do
o = object_double("LoadedClass::NOINSTANCE")
allow(o).to receive(:undefined_method)
end
it "uses the stubbed const value to verify against for `object_double(ConstName)`, " \
"which probably isn't what the user wants, but there's nothing else we can do since " \
"we can't get the constant name from the given object and thus cannot interrogate " \
"our stubbed const registry to see it has been stubbed" do
o = object_double(LoadedClass::NOINSTANCE)
allow(o).to receive(:defined_instance_method)
prevents { allow(o).to receive(:undefined_method) }
end
end
context "when an unloaded object constant has previously been stubbed with a class" do
before { stub_const("LoadedClass::NOINSTANCE", Class.new) }
it "treats it as being unloaded for `object_double('ConstName')`" do
o = object_double("LoadedClass::NOINSTANCE")
allow(o).to receive(:undefined_method)
end
it "treats it as being unloaded for `object_double(ConstName)`" do
o = object_double(LoadedClass::NOINSTANCE)
allow(o).to receive(:undefined_method)
end
end
end
end
end
|