File: any_instance.feature

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 (156 lines) | stat: -rw-r--r-- 6,229 bytes parent folder | download
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
Feature: Any Instance

  rspec-mocks provides two methods, `allow_any_instance_of` and
  `expect_any_instance_of`, that will allow you to stub or mock any instance of a class. They
  are used in place of [`allow`](../basics/allowing-messages) or [`expect`](../basics/expecting-messages):

  ```ruby
  allow_any_instance_of(Widget).to receive(:name).and_return("Wibble")
  expect_any_instance_of(Widget).to receive(:name).and_return("Wobble")
  ```

  These methods add the appropriate stub or expectation to all instances of `Widget`.

  You can also [configure the responses](../configuring-responses) in the same manner.

  This feature is sometimes useful when working with legacy code, though in general we
  discourage its use for a number of reasons:

  * The `rspec-mocks` API is designed for individual object instances, but this feature
    operates on entire classes of objects. As a result there are some semantically confusing
    edge cases. For example, in `expect_any_instance_of(Widget).to
    receive(:name).twice` it isn't clear whether a specific instance is expected to
    receive `name` twice, or if two receives total are expected. (It's the former.)
  * Using this feature is often a design smell. It may be that your test is trying to do too
    much or that the object under test is too complex.
  * It is the most complicated feature of `rspec-mocks`, and has historically received the
    most bug reports. (None of the core team actively use it, which doesn't help.)

  Scenario: Use `allow_any_instance_of` to stub a method
    Given a file named "example_spec.rb" with:
      """ruby
      RSpec.describe "allow_any_instance_of" do
        it "returns the specified value on any instance of the class" do
          allow_any_instance_of(Object).to receive(:foo).and_return(:return_value)

          o = Object.new
          expect(o.foo).to eq(:return_value)
        end
      end
      """
    When I run `rspec example_spec.rb`
    Then the examples should all pass

  Scenario: Use `allow_any_instance_of` to stub multiple methods
    Given a file named "example_spec.rb" with:
      """ruby
      RSpec.describe "allow_any_instance_of" do
        context "with receive_messages" do
          it "stubs multiple methods" do
            allow_any_instance_of(Object).to receive_messages(:foo => 'foo', :bar => 'bar')

            o = Object.new
            expect(o.foo).to eq('foo')
            expect(o.bar).to eq('bar')
          end
        end
      end
      """
    When I run `rspec example_spec.rb`
    Then the examples should all pass

  Scenario: Stubbing any instance of a class with specific arguments
    Given a file named "example_spec.rb" with:
      """ruby
      RSpec.describe "allow_any_instance_of" do
        context "with arguments" do
          it "returns the stubbed value when arguments match" do
            allow_any_instance_of(Object).to receive(:foo).with(:param_one, :param_two).and_return(:result_one)
            allow_any_instance_of(Object).to receive(:foo).with(:param_three, :param_four).and_return(:result_two)

            o = Object.new
            expect(o.foo(:param_one, :param_two)).to eq(:result_one)
            expect(o.foo(:param_three, :param_four)).to eq(:result_two)
          end
        end
      end
      """
    When I run `rspec example_spec.rb`
    Then the examples should all pass

  Scenario: Block implementation is passed the receiver as first arg
    Given a file named "example_spec.rb" with:
      """ruby
      RSpec.describe "allow_any_instance_of" do
        it 'yields the receiver to the block implementation' do
          allow_any_instance_of(String).to receive(:slice) do |instance, start, length|
            instance[start, length]
          end

          expect('string'.slice(2, 3)).to eq('rin')
        end
      end
      """
    When I run `rspec example_spec.rb`
    Then the examples should all pass

  Scenario: Use `expect_any_instance_of` to set a message expectation on any instance
    Given a file named "example_spec.rb" with:
      """ruby
      RSpec.describe "expect_any_instance_of" do
        before do
          expect_any_instance_of(Object).to receive(:foo)
        end

        it "passes when an instance receives the message" do
          Object.new.foo
        end

        it "fails when no instance receives the message" do
          Object.new.to_s
        end
      end
      """
    When I run `rspec example_spec.rb`
    Then it should fail with the following output:
      | 2 examples, 1 failure |
      | Exactly one instance should have received the following message(s) but didn't: foo |

  Scenario: Specify different return values for multiple calls in combination with allow_any_instance_of

    Using the multiple calls feature with `allow_any_instance_of` results in the behaviour where multiple calls are configured on every instance.
    Therefore, each individual instance will return the configured return values in the order specified, and then begin to repeat the last value.

    Given a file named "multiple_calls_spec_with_allow_any_instance_of.rb" with:
      """ruby
      class SomeClass
      end

      RSpec.describe "When the method is called multiple times on different instances with allow_any_instance_of" do
        it "demonstrates the mocked behavior on each instance individually" do
          allow_any_instance_of(SomeClass).to receive(:foo).and_return(1, 2, 3)

          first = SomeClass.new
          second = SomeClass.new
          third = SomeClass.new

          expect(first.foo).to eq(1)
          expect(second.foo).to eq(1)

          expect(first.foo).to eq(2)
          expect(second.foo).to eq(2)

          expect(first.foo).to eq(3)
          expect(first.foo).to eq(3) # repeats last value from here
          expect(second.foo).to eq(3)
          expect(second.foo).to eq(3) # repeats last value from here

          expect(third.foo).to eq(1)
          expect(third.foo).to eq(2)
          expect(third.foo).to eq(3)
          expect(third.foo).to eq(3) # repeats last value from here
        end
      end
      """
    When I run `rspec multiple_calls_spec_with_allow_any_instance_of.rb`
    Then the examples should all pass