Module: Shoulda::Matchers::Independent

Overview

This module provides matchers that are used to test behavior outside of Rails-specific classes.

Instance Method Summary collapse

Instance Method Details

#delegate_method(delegating_method) ⇒ DelegateMethodMatcher

The delegate_method matcher tests that an object forwards messages to other, internal objects by way of delegation.

In this example, we test that Courier forwards a call to #deliver onto its PostOffice instance:

require 'forwardable'

class Courier
  extend Forwardable

  attr_reader :post_office

  def_delegators :post_office, :deliver

  def initialize
    @post_office = PostOffice.new
  end
end

# RSpec
describe Courier do
  it { should delegate_method(:deliver).to(:post_office) }
end

# Minitest
class CourierTest < Minitest::Test
  should delegate_method(:deliver).to(:post_office)
end

You can also use delegate_method with Rails's delegate macro:

class Courier
  attr_reader :post_office
  delegate :deliver, to: :post_office

  def initialize
    @post_office = PostOffice.new
  end
end

describe Courier do
  it { should delegate_method(:deliver).to(:post_office) }
end

To employ some terminology, we would say that Courier's #deliver method is the delegating method, PostOffice is the delegate object, and PostOffice#deliver is the delegate method.

Qualifiers

as

Use as if the name of the delegate method is different from the name of the delegating method.

Here, Courier has a #deliver method, but instead of calling #deliver on the PostOffice, it calls #ship:

class Courier
  attr_reader :post_office

  def initialize
    @post_office = PostOffice.new
  end

  def deliver(package)
    post_office.ship(package)
  end
end

# RSpec
describe Courier do
  it { should delegate_method(:deliver).to(:post_office).as(:ship) }
end

# Minitest
class CourierTest < Minitest::Test
  should delegate_method(:deliver).to(:post_office).as(:ship)
end
with_prefix

Use with_prefix when using Rails's delegate helper along with the :prefix option.

class Page < ActiveRecord::Base
  belongs_to :site
  delegate :name, to: :site, prefix: true
  delegate :title, to: :site, prefix: :root
end

# RSpec
describe Page do
  it { should delegate_method(:name).to(:site).with_prefix }
  it { should delegate_method(:name).to(:site).with_prefix(true) }
  it { should delegate_method(:title).to(:site).with_prefix(:root) }
end

# Minitest
class PageTest < Minitest::Test
  should delegate_method(:name).to(:site).with_prefix
  should delegate_method(:name).to(:site).with_prefix(true)
  should delegate_method(:title).to(:site).with_prefix(:root)
end
with_arguments

Use with_arguments to assert that the delegate method is called with certain arguments. Note that this qualifier can only be used when the delegating method takes no arguments; it does not support delegating or delegate methods that take arbitrary arguments.

Here, when Courier#deliver_package calls PostOffice#deliver_package, it adds an options hash:

class Courier
  attr_reader :post_office

  def initialize
    @post_office = PostOffice.new
  end

  def deliver_package
    post_office.deliver_package(expedited: true)
  end
end

# RSpec
describe Courier do
  it do
    should delegate_method(:deliver_package).
      to(:post_office).
      with_arguments(expedited: true)
  end
end

# Minitest
class CourierTest < Minitest::Test
  should delegate_method(:deliver_package).
    to(:post_office).
    with_arguments(expedited: true)
end
allow_nil

Use allow_nil if the delegation accounts for the fact that your delegate object could be nil. (This is mostly intended as an analogue to the allow_nil option that Rails' delegate helper takes.)

class Account
  delegate :plan, to: :subscription, allow_nil: true
end

# RSpec
describe Account do
  it { should delegate_method(:plan).to(:subscription).allow_nil }
end

# Minitest
class PageTest < Minitest::Test
  should delegate_method(:plan).to(:subscription).allow_nil
end
with_private

Use with_private if the delegation accounts for the fact that your delegation is private. (This is mostly intended as an analogue to the private option that Rails' delegate helper takes.)

class Account
  delegate :plan, to: :subscription, private: true
end

# RSpec
describe Account do
  it { should delegate_method(:plan).to(:subscription).with_private }
end

# Minitest
class PageTest < Minitest::Test
  should delegate_method(:plan).to(:subscription).with_private
end


192
193
194
# File 'lib/shoulda/matchers/independent/delegate_method_matcher.rb', line 192

def delegate_method(delegating_method)
  DelegateMethodMatcher.new(delegating_method).in_context(self)
end