File: matching_arguments.feature

package info (click to toggle)
ruby-rspec 3.9.0c2e2m1s3-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,612 kB
  • sloc: ruby: 67,456; sh: 1,572; makefile: 98
file content (124 lines) | stat: -rw-r--r-- 6,471 bytes parent folder | download | duplicates (3)
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
Feature: Matching arguments

  Use `with` to specify the expected arguments. A [message expectation](../basics/expecting-messages) constrained by `with`
  will only be satisfied when called with matching arguments. A canned response for an
  [allowed message](../basics/allowing-messages) will only be used when the arguments match.

  | To match...                                         | ...use an expression like:         | ...which matches calls like:          |
  | --------------------------------------------------- | ---------------------------------  | ------------------------------------- |
  | Literal arguments                                   | `with(1, true)`                    | `foo(1, true)`                        |
  | Anything that supports case equality (`===`)        | `with(/bar/)`                      | `foo("barn")`                         |
  | Any list of args                                    | `with(any_args)`                   | `foo()`<br>`foo(1)`<br>`foo(:bar, 2)` |
  | Any sublist of args (like an arg splat)             | `with(1, any_args)`                | `foo(1)`<br>`foo(1, :bar, :bazz)`     |
  | An empty list of args                               | `with(no_args)`                    | `foo()`                               |
  | Anything for a given positional arg                 | `with(3, anything)`                | `foo(3, nil)`<br>`foo(3, :bar)`       |
  | Against an interface                                | `with(duck_type(:each))`           | `foo([])`                             |
  | A boolean                                           | `with(3, boolean)`                 | `foo(3, true)`<br>`foo(3, false)`     |
  | A subset of a hash                                  | `with(hash_including(:a => 1))`    | `foo(:a => 1, :b => 2)`               |
  | An excluded subset of a hash                        | `with(hash_excluding(:a => 1))`    | `foo(:b => 2)`                        |
  | A subset of an array                                | `with(array_including(:a, :b))`    | `foo([:a, :b, :c])`                   |
  | An instance of a specific class                     | `with(instance_of(Integer))`       |  `foo(3)`                             |
  | An object with a given module in its ancestors list | `with(kind_of(Numeric))`           | `foo(3)`                              |
  | An object with matching attributes                  | `with(having_attributes(:a => 1))` | `foo(:a => 1, :b => 2)`               |
  | Any RSpec matcher                                   | `with(<matcher>)`                  | `foo(<object that matches>)`          |

  Scenario: Basic example
    Given a file named "basic_example_spec.rb" with:
      """ruby
      RSpec.describe "Constraining a message expectation using with" do
        let(:dbl) { double }
        before { expect(dbl).to receive(:foo).with(1, anything, /bar/) }

        it "passes when the args match" do
          dbl.foo(1, nil, "barn")
        end

        it "fails when the args do not match" do
          dbl.foo(1, nil, "other")
        end
      end
      """
    When I run `rspec basic_example_spec.rb`
    Then it should fail with the following output:
      | 2 examples, 1 failure                                           |
      |                                                                 |
      | Failure/Error: dbl.foo(1, nil, "other")                         |
      |   #<Double (anonymous)> received :foo with unexpected arguments |
      |     expected: (1, anything, /bar/)                              |
      |          got: (1, nil, "other")                                 |

  Scenario: Using a RSpec matcher
    Given a file named "rspec_matcher_spec.rb" with:
      """ruby
      RSpec.describe "Using a RSpec matcher" do
        let(:dbl) { double }
        before { expect(dbl).to receive(:foo).with(a_collection_containing_exactly(1, 2)) }

        it "passes when the args match" do
          dbl.foo([2, 1])
        end

        it "fails when the args do not match" do
          dbl.foo([1, 3])
        end
      end
      """
    When I run `rspec rspec_matcher_spec.rb`
    Then it should fail with the following output:
      | 2 examples, 1 failure                                         |
      |                                                               |
      | Failure/Error: dbl.foo([1, 3])                                |
      | #<Double (anonymous)> received :foo with unexpected arguments |
      | expected: (a collection containing exactly 1 and 2)           |
      | got: ([1, 3])                                                 |

  Scenario: Using a custom matcher
    Given a file named "custom_matcher_spec.rb" with:
      """ruby
      RSpec::Matchers.define :a_multiple_of do |x|
        match { |actual| (actual % x).zero? }
      end

      RSpec.describe "Using a custom matcher" do
        let(:dbl) { double }
        before { expect(dbl).to receive(:foo).with(a_multiple_of(3)) }

        it "passes when the args match" do
          dbl.foo(12)
        end

        it "fails when the args do not match" do
          dbl.foo(13)
        end
      end
      """
    When I run `rspec custom_matcher_spec.rb`
    Then it should fail with the following output:
      | 2 examples, 1 failure                                           |
      |                                                                 |
      | Failure/Error: dbl.foo(13)                                      |
      |   #<Double (anonymous)> received :foo with unexpected arguments |
      |     expected: (a multiple of 3)                                 |
      |          got: (13)                                              |

  Scenario: Responding differently based on the arguments
    Given a file named "responding_differently_spec.rb" with:
      """ruby
      RSpec.describe "Using #with to constrain responses" do
        specify "its response depends on the arguments" do
          dbl = double

          # Set a default for any unmatched args
          allow(dbl).to receive(:foo).and_return(:default)

          allow(dbl).to receive(:foo).with(1).and_return(1)
          allow(dbl).to receive(:foo).with(2).and_return(2)

          expect(dbl.foo(0)).to eq(:default)
          expect(dbl.foo(1)).to eq(1)
          expect(dbl.foo(2)).to eq(2)
        end
      end
      """
    When I run `rspec responding_differently_spec.rb`
    Then the examples should all pass