← Back to Upcase

FactoryGirl and big hierarchies of records


(Radoslav Stankov) #1

Hi,

Lets say I have the following models:

class Account < ActiveRecord::Base
  belongs_to :user

  validates :user, presence: true
end

class Project < ActiveRecord::Base
  belongs_to :account

  validates :account, presence: true
end

class Task < ActiveRecord::Base
  belongs_to :project
  belongs_to :user

  validates :project, presence: true
  validates :user, presence: true
end

class Comment < ActiveRecord::Base
  belongs_to :task
  belongs_to :user

  validates :task, presence: true
  validates :user, presence: true
end

Which result in the following factories:

FactoryGirl.define do
  factory :user

  factory :account do
    user
  end

  factory :project do
    account
  end

  factory :task do
    project
    user
  end

  factory :comment do
    task
    user
  end
end

I try to use double or build :record whenever I can, but this is not always possible.
In some situations (like testing a scope or custom finder method) I need to have several create :comment.

Which generates 7 records per comment -> Comment (+ User) -> Task (+ User) -> Project -> Account (+ User)

I also can’t bypass validates :association, presence: true, since in the database I’m using a foreign key with NOT NULL constraints.

The application logic is strict - if you have e Comment you need to first have the rest of the stuff.
But most of the tests don’t care about it, they are generally interested only in Comment.

This is a simplified example. I my experience the connections are rarely so less and they grow with new features.

Any ideas how I can improve this situation in general?

p.s. My only idea is to have something like comment_lite which is something like:

factory :comment_lite, class: 'Comment' do
  task { any_existing_task_or_create_new_one }
  user { any_existing_user_or_create_new_one }
end

But this feels a bit dirty, brittle and probably will cause issues among the way.


(Derek Prior) #2

If presence of an association is required for your object to be valid then you should indeed create them as you are doing. You mentioned using doubles or build where possible, but you should also investigate build_stubbed. It won’t help where you actually need created records (scopes, etc), but it’s faster than build. build actually creates all associated objects.


(Samnang Chhun) #3

I found the same problem because most of times we do validations on associations. For example, in blog application, a blog post has to have an author, and comment has to have both commenter and blog post. And these associations should be validated, but whenever we create a comment, then it will create a couple of records in the DB.