Wrapping the original implementation

Use and_wrap_original to modify a partial double’s original response. This can be useful when you want to utilise an external object but mutate its response. For example if an API returns a large amount of data and for test purposes you’d like to trim it down. You can also use it to configure the default response for most arguments, and then override that for specific arguments using with.

Note: and_wrap_original is only supported on partial doubles, as normal test doubles do not have an original implementation.

Background

Given a file named “lib/api.rb” with:

class API
  def self.solve_for(x)
    (1..x).to_a
  end
end

and_wrap_original wraps the original partial double response

Given a file named “spec/andwraporiginal_spec.rb” with:

require 'api'

RSpec.describe "and_wrap_original" do
  it "responds as it normally would, modified by the block" do
    expect(API).to receive(:solve_for).and_wrap_original { |m, *args| m.call(*args).first(5) }
    expect(API.solve_for(100)).to eq [1,2,3,4,5]
  end
end

When I run rspec spec/and_wrap_original_spec.rb

Then the examples should all pass.

and_wrap_original can configure a default response that can be overridden for specific args

Given a file named “spec/andwraporiginal_spec.rb” with:

require 'api'

RSpec.describe "and_wrap_original" do
  it "can be overridden for specific arguments using #with" do
    allow(API).to receive(:solve_for).and_wrap_original { |m, *args| m.call(*args).first(5) }
    allow(API).to receive(:solve_for).with(2).and_return([3])

    expect(API.solve_for(20)).to eq [1,2,3,4,5]
    expect(API.solve_for(2)).to eq [3]
  end
end

When I run rspec spec/and_wrap_original_spec.rb

Then the examples should all pass.

and_wrap_original can configure a default response that can be overridden for specific keyword arguments

Given a file named “lib/kw_api.rb” with:

class API
  def self.solve_for(x: 1, y: 2)
    (x..y).to_a
  end
end

Given a file named “spec/andwraporiginal_spec.rb” with:

require 'kw_api'

RSpec.describe "and_wrap_original" do
  it "can be overridden for specific arguments using #with" do
    allow(API).to receive(:solve_for).and_wrap_original { |m, **kwargs| m.call(**kwargs).first(5) }
    allow(API).to receive(:solve_for).with(x: 3, y: 4).and_return([3])

    expect(API.solve_for(x: 1, y: 20)).to eq [1,2,3,4,5]
    expect(API.solve_for(y: 20)).to eq [1,2,3,4,5]
    expect(API.solve_for(x: 3, y: 4)).to eq [3]
  end
end

When I run rspec spec/and_wrap_original_spec.rb

Then the examples should all pass.