factory_bot icon indicating copy to clipboard operation
factory_bot copied to clipboard

Underscores being removed from class name during tests

Open luizkowalski opened this issue 2 years ago • 5 comments

Description

hey team 👋🏻

I'm currently trying to move away from defining the class attribute as a class to a string. The thing is, in this project, for different reasons, some classes have an underscore in their names. That is not going to change and it is like that for different reasons.

Currently some factories are defined like this:

factory :customs_declaration_nl_ddu_1, class: Customs::Declarations::NL::DDU_1_0

When I correct to String, like this

factory :customs_declaration_nl_ddu_1, class: "Customs::Declarations::NL::DDU_1_0"

errors like below start to pop up:

 Failure/Error: products: build_list(:customs_product_ddu, 1))

       NameError:
         uninitialized constant Customs::Products::NL::DDU10

Reproduction Steps

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"
  git_source(:github) { |repo| "https://github.com/#{repo}.git" }
  gem "factory_bot", "~> 6.0"
  gem "activerecord"
  gem "sqlite3"
end

require "active_record"
require "factory_bot"
require "minitest/autorun"
require "logger"

ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  # TODO: Update the schema to include the specific tables or columns necessary
  # to reproduct the bug
  create_table :posts, force: true do |t|
    t.string :body
  end
end

# TODO: Add any application specific code necessary to reproduce the bug
class Post_3_D < ActiveRecord::Base
  self.table_name = "posts"
end

FactoryBot.define do
  # TODO: Write the factory definitions necessary to reproduce the bug
  factory :post, class: "Post_3_D" do
    body { "Post body" }
  end
end

class FactoryBotTest < Minitest::Test
  def test_factory_bot_stuff
    # TODO: Write a failing test case to demonstrate what isn't working as
    # expected
    body_override = "Body override"

    post = FactoryBot.build(:post, body: body_override)

    assert_equal post.body, body_override
  end
end

Expected behavior

Underscores are not to be removed from the class name

Actual behavior

System configuration

factory_bot version: 6.2.0 rails version: 7.0.6 ruby version: 3.2.2

luizkowalski avatar Aug 18 '23 13:08 luizkowalski

That's happening because of a call to camelize https://github.com/thoughtbot/factory_bot/blob/4a37cb64090d6354a719e8c5ef73653f5d242017/lib/factory_bot/factory.rb#L26. It might be tricky to handle that without breaking other cases (we could maybe skip camelize if there are already capital letters? But it's bound to break something for somebody). The only workaround at the moment is continuing to use the contant instead of a string 😢.

composerinteralia avatar Aug 18 '23 14:08 composerinteralia

I see the problem...out of curiosity, why is camelize being called anyway? According to the docs you can either pass the class name as String or the class itself. In both cases to_s.constantize should be sufficient, no? What are other people doing that require a call to camelize?

luizkowalski avatar Aug 18 '23 14:08 luizkowalski

"namespace/model".camelize => "Namespace::Model"

composerinteralia avatar Aug 18 '23 14:08 composerinteralia

ah so "namespace/model" is a valid class parameter then

luizkowalski avatar Aug 18 '23 14:08 luizkowalski

I understand that our use case might be too specific and it's not worth updating the library to solve an edge case like this. If you think there is something of value here, it is fine otherwise, I think this can be closed.

I appreciate the help!

luizkowalski avatar Aug 18 '23 14:08 luizkowalski

@luizkowalski a bit late, but we were able to resolve this issue in https://github.com/thoughtbot/factory_bot/pull/1642. hope this helps your use case!

stephanieminn avatar May 20 '24 14:05 stephanieminn

thanks a lot, that's great!

luizkowalski avatar May 20 '24 14:05 luizkowalski