Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scarroll32/7ed6e170a983a0580d9e190eda4c2575 to your computer and use it in GitHub Desktop.
Save scarroll32/7ed6e170a983a0580d9e190eda4c2575 to your computer and use it in GitHub Desktop.

It can be difficult to test the different scenarious for a module intended for use by including in another class.

If the class is statically defined in the spec, any later definitions extend, not replace, the first definition - which can cause test issues and breaks isolation between examples.

RSpec.describe SomeModule do
  class SomeIncluder
    include SomeModule
  end
  
  it "configures something" do
    SomeIncluder.some_config = :some_val
  end
  
  it "does something else" do
    puts SomeIncluder.some_config
    # => :some_val                    <= No example isolation
  end
  
  context "when some other scenario" do
    class SomeIncluder
      include SomeModule
      
      some_other_config :some_other_val
    end
    it "does something else"
      puts SomeIncluder.some_config
      # => :some_val                    <= defining class re-opens the class defintion (doesn't replace)
    end
  
  end
  
  
...

Alternatively, N differently named class definitions for N different scenarios is hard to manage.

A better solution is to create the class anonymously for the given scenario:

using an anonymous class to test module functionality on the including class

RSpec.describe SomeModule do
  let(:object) { klass.new }
  let(:klass) do
    # anonymous class, unique every time it is created
    Class.new do
      include SomeModule
    end
  end
  
  context "when configured some other way" do
    let(:klass) do
      Class.new do
        include SomeModule
        
        some_configuration :some_value
      end
    end
  end
...

If you need the mock class to have a name, define the anonymous class as a constant

RSpec.describe SomeModule do
  let(:object) { klass.new }
  let(:klass) do
    # anonymous class, unique every time it is created
    k = Class.new do
      include SomeModule
    end
    Object.const_set "SomeModuleIncluder#{rand(10000)}", k
  end
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment