Git Product home page Git Product logo

factory_bot-preload's Introduction

factory_bot-preload

ruby-tests Gem Gem

We all love Rails fixtures because they're fast, but we hate to deal with YAML/CSV/SQL files. Here enters factory_bot (FB).

Now, you can easily create records by using predefined factories. The problem is that hitting the database everytime to create records is pretty slow. And believe me, you'll feel the pain when you have lots of tests/specs.

So here enters Factory Bot Preload (FBP). You can define which factories will be preloaded, so you don't have to recreate it every time (that will work for 99.37% of the time, according to statistics I just made up).

Installation

gem install factory_bot-preload

Intructions

Setup

Add both FB and FBP to your Gemfile:

source "https://rubygems.org"

gem "rails"
gem "pg"

group :test, :development do
  gem "factory_bot"
  gem "factory_bot-preload", require: false
end

Notice that adding require: false is important; otherwise you won't be able to run commands such as rails db:test:prepare.

RSpec Setup

On your spec/spec_helper.rb file, make sure that transactional fixtures are enabled. Here's is my file without all those RSpec comments:

ENV["RAILS_ENV"] ||= "test"
require File.expand_path("../../config/environment", __FILE__)
require "rspec/rails"

# First, load factory_bot/preload.
require "factory_bot/preload"

# Then load your factories
Dir[Rails.root.join("spec/support/factories/**/*.rb")].each do |file|
  require file
end

RSpec.configure do |config|
  config.use_transactional_fixtures = true
  config.mock_with :rspec
end

You may want to configure the generated helper names. For instance, imagine you have a namespace like MyApp::Models::User. That'd generate a helper method like myapp_models_user. If you don't have conflicting names, you can strip myapp_models_ like this:

FactoryBot::Preload.helper_name = lambda do |class_name, helper_name|
  helper_name.gsub(/^myapp_models_/, "")
end

Minitest Setup

On your test/test_helper.rb file, make sure that transaction fixtures are enabled. Here's what your file may look like:

ENV["RAILS_ENV"] ||= "test"
require_relative "../config/environment"
require "rails/test_help"

module ActiveSupport
  class TestCase
    self.use_instantiated_fixtures = true
  end
end

# First, load factory_bot/preload.
require "factory_bot/preload"

# Then load your factories.
Dir["./test/support/factories/**/*.rb"].each do |file|
  require file
end

# Finally, setup minitest.
# Your factories won't behave correctly unless you
# call `FactoryBot::Preload.minitest` after loading them.
FactoryBot::Preload.minitest

Usage

Create your factories and load it from your setup file (either test/test_helper.rb or spec/spec_helper.rb) You may have something like this:

FactoryBot.define do
  factory :user do
    name "John Doe"
    sequence(:email) {|n| "john#{n}@example.org" }
    sequence(:username) {|n| "john#{n}" }
    password "test"
    password_confirmation "test"
  end

  factory :projects do
    name "My Project"
    association :user
  end
end

To define your preloadable factories, just use the preload method:

FactoryBot.define do
  factory :user do
    name "John Doe"
    sequence(:email) {|n| "john#{n}@example.org" }
    sequence(:username) {|n| "john#{n}" }
    password "test"
    password_confirmation "test"
  end

  factory :projects do
    name "My Project"
    association :user
  end

  preload do
    factory(:john) { create(:user) }
    factory(:myapp) { create(:project, user: users(:john)) }
  end
end

You can also use preloaded factories on factory definitions.

FactoryBot.define do
  factory :user do
    # ...
  end

  factory :projects do
    name "My Project"
    user { users(:john) }
  end

  preload do
    factory(:john) { create(:user) }
    factory(:myapp) { create(:project, user: users(:john)) }
  end
end

Like Rails fixtures, FBP will define methods for each model. You can use it on your examples and alike.

require "test_helper"

class UserTest < ActiveSupport::TestCase
  test "returns john's record" do
    assert_instance_of User, users(:john)
  end

  test "returns myapp's record" do
    assert_equal users(:john), projects(:myapp).user
  end
end

Or if you're using RSpec:

require "spec_helper"

describe User do
  let(:user) { users(:john) }

  it "returns john's record" do
    users(:john).should be_an(User)
  end

  it "returns myapp's record" do
    projects(:myapp).user.should == users(:john)
  end
end

That's it!

Maintainer

Contributors

Contributing

For more details about how to contribute, please read https://github.com/fnando/factory_bot-preload/blob/main/CONTRIBUTING.md.

License

The gem is available as open source under the terms of the MIT License. A copy of the license can be found at https://github.com/fnando/factory_bot-preload/blob/main/LICENSE.md.

Code of Conduct

Everyone interacting in the factory_bot-preload project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

factory_bot-preload's People

Contributors

brunoadacosta avatar brunoarueira avatar danieltamiosso avatar dbalexandre avatar dependabot[bot] avatar fabiomr avatar fnando avatar gustavodiel avatar mhfs avatar ozeias avatar thiagopradi avatar yujideveloper avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

factory_bot-preload's Issues

undefined method `Factory' for #<Object:0x007fd5a0740ef0> (NoMethodError)

FactoryGirl.define do
  factory :user do
    name "Jane Doe"
    sequence(:email) { |n| "jane#{n}@example.org" }
    password "password"
    password_confirmation "password"
  end

  preload do
    factory(:jane)  { Factory(:user) }
  end
end

in spec/factories/users.rb

/usr/src/app/spec/factories/users.rb:10:in `block (3 levels) in <top (required)>': undefined method `Factory' for #<Object:0x007fd5a0740ef0> (NoMethodError)
    from /usr/local/bundle/gems/factory_girl-preload-2.3.1/lib/factory_girl/preload/helpers.rb:49:in `instance_eval'
    from /usr/local/bundle/gems/factory_girl-preload-2.3.1/lib/factory_girl/preload/helpers.rb:49:in `factory_set'
    from /usr/local/bundle/gems/factory_girl-preload-2.3.1/lib/factory_girl/preload/helpers.rb:28:in `factory'
    from /usr/src/app/spec/factories/users.rb:10:in `block (2 levels) in <top (required)>'
    from /usr/local/bundle/gems/factory_girl-preload-2.3.1/lib/factory_girl/preload.rb:41:in `instance_eval'
    from /usr/local/bundle/gems/factory_girl-preload-2.3.1/lib/factory_girl/preload.rb:41:in `block (2 levels) in run'
    from /usr/local/bundle/gems/factory_girl-preload-2.3.1/lib/factory_girl/preload.rb:40:in `each'
    from /usr/local/bundle/gems/factory_girl-preload-2.3.1/lib/factory_girl/preload.rb:40:in `block in run'
    from /usr/local/bundle/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `block in transaction'
    from /usr/local/bundle/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/transaction.rb:184:in `within_new_transaction'
    from /usr/local/bundle/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
    from /usr/local/bundle/gems/factory_girl-preload-2.3.1/lib/factory_girl/preload.rb:39:in `run'
    from /usr/local/bundle/gems/factory_girl-preload-2.3.1/lib/factory_girl/preload/rspec2.rb:9:in `block (2 levels) in <top (required)>'
    from /usr/local/bundle/gems/rspec-core-3.3.2/lib/rspec/core/example.rb:378:in `instance_exec'
    from /usr/local/bundle/gems/rspec-core-3.3.2/lib/rspec/core/example.rb:378:in `instance_exec'
    from /usr/local/bundle/gems/rspec-core-3.3.2/lib/rspec/core/hooks.rb:357:in `run'
    from /usr/local/bundle/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1660:in `block in run_hooks_with'
    from /usr/local/bundle/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1660:in `each'
    from /usr/local/bundle/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1660:in `run_hooks_with'
    from /usr/local/bundle/gems/rspec-core-3.3.2/lib/rspec/core/configuration.rb:1626:in `with_suite_hooks'
    from /usr/local/bundle/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb:114:in `block in run_specs'
    from /usr/local/bundle/gems/rspec-core-3.3.2/lib/rspec/core/reporter.rb:77:in `report'
    from /usr/local/bundle/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb:113:in `run_specs'
    from /usr/local/bundle/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb:89:in `run'
    from /usr/local/bundle/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb:73:in `run'
    from /usr/local/bundle/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb:41:in `invoke'
    from /usr/local/bundle/gems/rspec-core-3.3.2/exe/rspec:4:in `<main>'
/usr/local/bin/ruby -I/usr/local/bundle/gems/rspec-core-3.3.2/lib:/usr/local/bundle/gems/rspec-support-3.3.0/lib /usr/local/bundle/gems/rspec-core-3.3.2/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb failed

const_get': uninitialized constant Read (NameError)

I am getting the fallowing error:
gems/factory_girl-1.3.3/lib/factory_girl/factory.rb:355:in `const_get': uninitialized constant Read (NameError)

where I have the definition:

Factory.define :read do |f|
 f.name 'Read'
 f.alias 'read'
end

and a preload definition as :

 Factory.preload do 
  factory(:private_message_status_read)     { Factory(:read) }
 end

I used the logger and made sure the definition of : read is being executed before the loading.
What might be going wrong ? Any ideas?

Improve readme

What do you think about change the README to markdown in favor of github-flavored-markdown that turns the code much more readable?

Can I do this?

`factory_get': undefined method `[]' for nil:NilClass (NoMethodError)

Hi @fnando,

I am trying to run my suite with associations in preload but is returning this error. This happens when I try to load an association of another model!

factory :product do
...
association: category, factory: :category
end

preload do
ย  factory (:promotion) { create (:product, category: categories(:promotion)) }
end

Specified error:

gems/factory_girl-preload-2367d17f5d6e/lib/factory_girl/preload/helpers.rb:34:in factory_get': undefined method[]' for nil:NilClass (NoMethodError)

Rspec 3.5 + factory_girl-preload are not rolling back on each test

Hy guys,

I'm trying to configure the RSpec 3.5 and factory_girl-preload 2.3.1 on Rails 5 as a usually do since Rails 2.

I just realized that something has changed on RSpec 3.5 regarding the option use_transactional_fixtures I've noticed that they are not using savepoint anymore, but are using begin/commit transactions. The problems is that, as I'm using a shared connection, every time that I change something on the database it runs a new begin/commit transaction and I'm suspecting that the rollback is not working for this case, because I'm getting some preloaded factories with different data when I run the whole suite, and the tests are running fine when I run a single suite.

Hope you guys could help here, not sure if this must be fixed on this gem or we must report this problem on the RSpec issues.

undefined method root for Nil class, from preload helper included method

I'm getting this exception while running the rspecs, any suggestion would help

stack trace

/Users/kdewade/.rvm/gems/ruby-2.1.2xxxxxx/gems/factory_girl-preload-2.3.0/lib/factory_girl/preload/helpers.rb:9:in `included': undefined method `root' for nil:NilClass (NoMethodError)
    from /Users/kdewade/.rvm/gems/ruby-2.1.2xxxxxx/gems/factory_girl-preload-2.3.0/lib/factory_girl/preload.rb:11:in `include'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2xxxxxx/gems/factory_girl-preload-2.3.0/lib/factory_girl/preload.rb:11:in `<module:Preload>'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2xxxxxx/gems/factory_girl-preload-2.3.0/lib/factory_girl/preload.rb:4:in `<module:FactoryGirl>'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2xxxxxx/gems/factory_girl-preload-2.3.0/lib/factory_girl/preload.rb:3:in `<top (required)>'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2xxxxxx/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:247:in `require'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2xxxxxx/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:247:in `block in require'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2xxxxxx/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:232:in `load_dependency'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2xxxxxx/gems/activesupport-4.1.4/lib/active_support/dependencies.rb:247:in `require'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2xxxxxx/gems/factory_girl-preload-2.3.0/lib/factory_girl-preload.rb:1:in `<top (required)>'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2@global/gems/bundler-1.6.2/lib/bundler/runtime.rb:76:in `require'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2@global/gems/bundler-1.6.2/lib/bundler/runtime.rb:76:in `block (2 levels) in require'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2@global/gems/bundler-1.6.2/lib/bundler/runtime.rb:72:in `each'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2@global/gems/bundler-1.6.2/lib/bundler/runtime.rb:72:in `block in require'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2@global/gems/bundler-1.6.2/lib/bundler/runtime.rb:61:in `each'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2@global/gems/bundler-1.6.2/lib/bundler/runtime.rb:61:in `require'
    from /Users/kdewade/.rvm/gems/ruby-2.1.2@global/gems/bundler-1.6.2/lib/bundler.rb:132:in `require' 

Problem with abstract classes

Hey thanks for this cool gem! I ran into an issue with abstract classes that inherit from ActiveRecord::Base

class Foo < Bar
end

class Bar < ActiveRecord::Base
  self.abstract_class = true
end

Where Foo has a table but Bar doesn't.

When clean runs:

names = active_record.descendants.collect(&:table_name).uniq if names.empty?

It returns nil for Bar, since it doesn't have a table, and results in a db error

I'm wondering if it should also do something like:

names.delete_if { |n| n.nil? }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.