Chowlett
Chowlett

Reputation: 46675

How best to test class that depends on constants in another file?

I'm writing a Ruby library - call it module MyLibrary - which depends upon a data parser. The parser is specific to the library, but may need to be swapped out for a different parser at a later date, so it makes sense to have it be a class nested in MyLibrary - class MyLibrary::Parser.

MyLibrary exposes a few exception types to the client, and the Parser may hit situations where it wants to raise these exceptions (and MyLibrary is happy to pass them through). So I have the following arrangement:

my_library.rb:

require 'parser'
module MyLibrary
  class SomeException < RuntimeError
  end

  def self.do_it
    parser = Parser.new
    parser.parse_it
  end
end

parser.rb

module MyLibrary
 class Parser
   def parse_it
     if bad_stuff
       raise SomeException, "Argh"
     end
   end
 end
end

Now, I want to unit-test Parser using rspec.

parser_spec.rb

require 'parser'

RSpec.describe Parser do
  it 'raises when bad stuff happens' do
    expect { Parser.new.parse_it }.to raise_error(MyLibrary::SomeException)
  end
end

But because I'm unit-testing the Parser and my_library.rb hasn't been required in, SomeException isn't defined.

What's my best method for providing SomeException within Parser's spec? Or am I going about this in completely the wrong way?

Upvotes: 1

Views: 67

Answers (2)

Raj
Raj

Reputation: 1784

I think there are 2 things you could consider.

  1. Building on maxple's comment, unless you have a specific reason for it, the SomeException class could just be defined in parser.rb. That class is the one raising the error, the spec test would work, and anyone requiring that file would have access to that exception. Since you don't even reference it in my_library.rb it seems like it would be fine. Another behavioral reason that supports this approach is if the error is a "Parsing" error, the exception name should reflect that and the Parser is the class that should own that. If the MyLibrary class is just forwarding any exception along, it doesn't matter what it is and it shouldn't be defined there.

  2. If you want to keep the exception defined in my_library.rb, then I would suggest using a spec_helper.rb file, that lives in your spec folder, to load your full library. This is usually done by requiring your top level lib/my_library.rb file. Rspec commonly adds your top level lib folder to the ruby include path for just this purpose. Then each and every spec test file you write should require 'spec_helper'. In my experience this is probably the most idiomatic way to load all common dependencies for unit testing in rspec.

Upvotes: 2

Tomasz
Tomasz

Reputation: 274

I haven't done much in rspec but wouldn't it help if you move the require 'parser' line from my_library.rb to parser.rb? The way I see it it's the Parser that needs that exception not the other way around.

Like I said my knowledge in this case is limited but I hope that will help, if not good luck in the search! :)

Upvotes: -1

Related Questions