File: null_object_double_spec.rb

package info (click to toggle)
ruby-rspec 3.13.0c0e0m0s1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,856 kB
  • sloc: ruby: 70,868; sh: 1,423; makefile: 99
file content (135 lines) | stat: -rw-r--r-- 4,296 bytes parent folder | download | duplicates (4)
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
module RSpec
  module Mocks
    RSpec.describe "a double _not_ acting as a null object" do
      before(:each) do
        @double = double('non-null object')
      end

      it "says it does not respond to messages it doesn't understand" do
        expect(@double).not_to respond_to(:foo)
      end

      it "says it responds to messages it does understand" do
        allow(@double).to receive(:foo)
        expect(@double).to respond_to(:foo)
      end

      it "raises an error when interpolated in a string as an integer" do
        # Not sure why, but 1.9.2 (but not JRuby --1.9) raises a different
        # error than 1.8.7 and 1.9.3...
        expected_error = (RUBY_VERSION == '1.9.2' && RUBY_PLATFORM !~ /java/) ?
                         RSpec::Mocks::MockExpectationError :
                         TypeError

        expect { "%i" % @double }.to raise_error(expected_error)
      end
    end

    RSpec.describe "a double acting as a null object" do
      before(:each) do
        @double = double('null object').as_null_object
      end

      it "says it responds to everything" do
        expect(@double).to respond_to(:any_message_it_gets)
      end

      it "allows explicit stubs" do
        allow(@double).to receive(:foo) { "bar" }
        expect(@double.foo).to eq("bar")
      end

      it "allows explicit expectation" do
        expect(@double).to receive(:something)
        @double.something
      end

      it 'returns a string from `to_str`' do
        expect(@double.to_str).to be_a(String)
      end

      it 'continues to return self from an explicit expectation' do
        expect(@double).to receive(:bar)
        expect(@double.foo.bar).to be(@double)
      end

      it 'returns an explicitly stubbed value from an expectation with no implementation' do
        allow(@double).to receive_messages(:foo => "bar")
        expect(@double).to receive(:foo)
        expect(@double.foo).to eq("bar")
      end

      it "fails verification when explicit exception not met" do
        expect {
          expect(@double).to receive(:something)
          verify @double
        }.to fail
      end

      it "ignores unexpected methods" do
        @double.random_call("a", "d", "c")
        verify @double
      end

      it 'allows unexpected message sends using `send`' do
        val = @double.send(:foo).send(:bar)
        expect(val).to equal(@double)
      end

      it 'allows unexpected message sends using `__send__`' do
        val = @double.__send__(:foo).__send__(:bar)
        expect(val).to equal(@double)
      end

      it "allows expected message with different args first" do
        expect(@double).to receive(:message).with(:expected_arg)
        @double.message(:unexpected_arg)
        @double.message(:expected_arg)
      end

      it "allows expected message with different args second" do
        expect(@double).to receive(:message).with(:expected_arg)
        @double.message(:expected_arg)
        @double.message(:unexpected_arg)
      end

      it "can be interpolated in a string as an integer" do
        # This form of string interpolation calls
        # @double.to_int.to_int.to_int...etc until it gets an integer,
        # and thus gets stuck in an infinite loop unless our double
        # returns an int value from #to_int.
        expect(("%i" % @double)).to eq("0")
      end

      it "does not allow null objects to be used outside of examples" do
        RSpec::Mocks.teardown

        expect { @double.some.long.message.chain }.to raise_error(RSpec::Mocks::OutsideOfExampleError)
        expect { @double.as_null_object }.to raise_error(RSpec::Mocks::OutsideOfExampleError)
      end
    end

    RSpec.describe "#as_null_object" do
      it "sets the object to null_object" do
        obj = double('anything').as_null_object
        expect(obj).to be_null_object
      end
    end

    RSpec.describe "#null_object?" do
      it "defaults to false" do
        obj = double('anything')
        expect(obj).not_to be_null_object
      end
    end

    RSpec.describe "when using the :expect syntax" do
      include_context "with syntax", :expect

      it 'still supports null object doubles' do
        obj = double("foo").as_null_object
        expect(obj.foo.bar.bazz).to be(obj)
      end
    end
  end
end