jedi
jedi

Reputation: 2200

RSpec test class from within a module without the actual file

I have a module for creating parts (products) in my store called ErpPartsService::Builder and withing the module I have built a helper class CategoryByLauberIdFetcher that I just use internally within the module, not anywhere else. I have it inside the file app/services/erp_parts_service/builder.rb.

Here's my code:

module ErpPartsService
  class CategoryByLauberIdFetcher < Service # This is the helper class that I want to test.
    def initialize(...)
      ...
    end

    def call(lauber_id:)
      ...
    end
  end

  class Builder < Service
    def initialize(
      category_by_lauber_id: CategoryByLauberIdFetcher
    )
      @category_by_lauber_id = category_by_lauber_id
    end

    def call(...)
      ...
    end

    private

    def get_category_by_lauber_id(id)
      @category_by_lauber_id.call(lauber_id: id)
    end
  end
end

I wrote tests for CategoryByLauberIdFetcher within spec/services/erp_parts_service/category_by_lauber_id_fetcher_spec.rb

RSpec.describe ErpPartsService::CategoryByLauberIdFetcher do
  it '...' do
    ...
  end
end

When I run them I get:

NameError:
  uninitialized constant ErpPartsService::CategoryByLauberIdFetcher

I wrote tests for Builder class within spec/services/erp_parts_service/builder_spec.rb

RSpec.describe ErpPartsService::Builder do
  it '...' do
    ...
  end
end

And they work fine. What am I missing?

Upvotes: 0

Views: 165

Answers (1)

Greg
Greg

Reputation: 6628

It looks like an autoloader issue:

  1. Seeing the constant ErpPartsService::Builder the autoloader expects a file erp_parts_service/builder.rb and it finds it... but

  2. Seeing ErpPartsService::CategoryByLauberIdFetcher autoloader tries to find erp_parts_service/category_by_lauber_id_fetcher.rb and fails, because definition of this class is in erp_parts_service/builder.rb

Add require to explicitly load the file containing the class you're trying to test.

require 'erp_parts_service/builder.rb'
RSpec.describe ErpPartsService::CategoryByLauberIdFetcher do
  it '...' do
    ...
  end
end

Or (better yet) put each class in a separate file and stick to the convention. Not only the autoloader, but other people joining your project would look for this class in a file that doesn't exist.

I know you've mentioned that you want to use this class only inside your module, but that's not the way to make it "private". You just made it annoying to use it instead of protecting it from being used.

Upvotes: 1

Related Questions