0

I want to write rspec test to verify a class method which invokes the included module method by the class name. When I call the module method using the Module name it works fine, but throws NoMethodError when invoked by class name.

module Test
  def self.module_mtd
    p "test"
  end
end

class Burger 
  include Test

  attr_reader :options

  def initialize(options={})
    @options = options
  end

  def apply_ketchup
    @ketchup = @options[:ketchup]
  end

  def has_ketchup_on_it?
    Burger.module_mtd # Throws NoMethodError
    Test.module_mtd #Works fine as expected
    @ketchup
  end
end


describe Burger do
  describe "#apply_ketchup" do
    subject { burger }
    before  { burger.apply_ketchup }

    context "with ketchup" do
      let(:burger) { Burger.new(:ketchup => true) }

      it { should have_ketchup_on_it }
    end

    context "without ketchup" do
      let(:burger) { Burger.new(:ketchup => false) }

      it { should_not have_ketchup_on_it }
    end
  end
end
  • `include Test` should be on its own line. A class declaration should only look like `class Foo` or `class Foo < Bar`. I'm kind of suprised that its not a syntax error (its still pretty bad style though). – max Apr 30 '17 at 14:39
  • I usually follow that convention. Just was in a hurry to post the question. Thanks for pointing out. – Gautham Durairaj Apr 30 '17 at 14:43

1 Answers1

1

The problem is not the test itself but your understanding of how class methods work in Ruby.

module Test
  def self.module_mtd
    p "test"
  end
end

Declares a method belonging to Test. Unlike the modules instance methods this is not added to the class when you include the module.

To declare a class method from a module you need to use the module mixins pattern to extend the singleton class:

module Test
  # this is called when you include the module
  def self.included(base)
    # this adds the class methods to the class
    base.extend ClassMethods
  end

  module ClassMethods
    def foo
      puts "hello world"
    end
  end
end

The fact that module ClassMethods declares foo as an instance method can seem kind of confusing until you realize that the singleton class that you are extending is an instance of "Class".

See:

Community
  • 1
  • 1
max
  • 96,212
  • 14
  • 104
  • 165