1
votes

Disclaimers:

  • I'm pretty new to ruby
  • Please don't ask me why I'm using the same class name in two different modules. I'm only trying to understand why rspec behaves this way; I found it confusing and could not find answers online.

Description of issue:

  • I have two .rb files in /lib.
  • Both have a class with the name FooClass, but under different modules (NamespaceOne, NamespaceTwo).
  • Yet, when I run rspec, one test fails because it runs against the wrong class and the failure message looks weird, i.e. a part of the failure message implies that it's looking at NamespaceOne, while it's clear that it actually tried running the test against NamespaceTwo.

My question: Why does rspec behaves this way? What am I missing?

Here's what I have in the lib folder:

lib/one.rb:

module NamespaceOne

  class FooClass
    def self.method_one(input)
      1
    end
  end
end

lib/two.rb:

module NamespaceTwo

  class FooClass
    def self.method_two(input)
      2
    end
  end
end

, here are the two corresponding specs:

spec/one_spec.rb

require "one"

include NamespaceOne

describe FooClass do

    describe ".method_one" do
        context "given an empty string" do
            it "returns 1" do
                expect(FooClass.method_one("")).to eql(1)
            end
        end
    end

end

and spec/two_spec.rb

require "two"

include NamespaceTwo

describe FooClass do

    describe ".method_two" do
        context "given an empty string" do
            it "returns 2" do
                expect(FooClass.method_two("")).to eql(2)
            end
        end
    end

end

Finally, rspec output:

$ bundle exec rspec --format documentation

NamespaceOne::FooClass
  .method_one
    given an empty string
      returns 1 (FAILED - 1)

NamespaceTwo::FooClass
  .method_two
    given an empty string
      returns 2

Failures:

  1) NamespaceOne::FooClass.method_one given an empty string returns 1
     Failure/Error: expect(FooClass.method_one("")).to eql(1)

     NoMethodError:
       undefined method `method_one' for NamespaceTwo::FooClass:Class
       Did you mean?  method_two
     # ./spec/one_spec.rb:10:in `block (4 levels) in <top (required)>'

Finished in 0.00201 seconds (files took 0.08006 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec/one_spec.rb:9 # NamespaceOne::FooClass.method_one given an empty string returns 1

Note: In the tests/examples, if I call the method using the full namespace, the tests do pass. i.e the following tweaks in their respective spec files make the tests pass,

spec/one_spec.rb

expect(NamespaceOne::FooClass.method_one("")).to eql(1)

spec/two_spec.rb

expect(NamespaceTwo::FooClass.method_two("")).to eql(2)

but I don't understand why 'include'ing the modules as I did isn't enough.

1
did I answer your question? - Anthony

1 Answers

0
votes

when you do

require "one"

include NamespaceOne

describe FooClass do

you're including NamespaceOne in Object, but ruby doesn't know that the next namespace FooClass should resolve to NamspaceOne. That's because it's done lexically (https://stackoverflow.com/a/20848317/3109182). Instead use the full namespace when describing, that way rspec and ruby knows which constants to resolve to:

require "one"    
describe NamespaceOne::FooClass do
end