factory_bot build_stubbed strategy
Asked Answered
S

1

7

The factory_bot documentation for build strategies says:

factory_bot supports several different build strategies: build, create, attributes_for and build_stubbed

And continues with some examples of usage. However, it doesn't clearly state what the result of each one is. I've been using create and build for a while now. attributes_for seems straightforward from the description and I see some uses for it. However, what is build_stubbed? The description says

Returns an object with all defined attributes stubbed out

What does "stubbed out" mean? How is this different from either create or build?

Shirtwaist answered 17/6, 2022 at 17:19 Comment(0)
W
14

Let's consider the difference on the example of these factories:

FactoryBot.define do
  factory :post do
    user
    title { 'Post title' }
    body { 'Post body' } 
  end
end

FactoryBot.define do
  factory :user do
    first_name { 'John' }
    last_name { 'Doe' }
  end
end

build

With build method everything is easy. It returns a Post instance that's not saved

# initialization
post = FactoryBot.build(:post)
# call

p post
p post.user
# output
#<Post:0x00007fd10f824168> {
   :id => nil,
   :user_id => nil,
   :title => "Post title",
   :body => "Post body",
   :created_at => nil,
   :updated_at => nil
}

#<User:0x00007f8792ed9290> {
  :id => nil,
  :first_name => "Post title",
  :last_name => "Post body",
  :created_at => nil,
  :updated_at => nil
}
Post.all # => []
User.all # => []

create

With create everything is also quite obvious. It saves and returns a Post instance. But it calls all validations and callbacks and also creates associated instance of User

# initialization
post = FactoryBot.create(:post)
# call

p post
p post.user
# output

#<Post:0x00007fd10f824168> {
   :id => 1,
   :user_id => 1,
   :title => "Post title",
   :body => "Post body",
   :created_at => Sat, 18 Jun 2022 05:32:17.122906000 UTC +00:00,
   :updated_at => Sat, 18 Jun 2022 05:32:17.122906000 UTC +00:00
}
#<User:0x00007f8792ed9290> {
  :id => 1,
  :first_name => "John",
  :last_name => "Joe",
  :created_at => Sat, 18 Jun 2022 05:32:17.122906000 UTC +00:00,
  :updated_at => Sat, 18 Jun 2022 05:32:17.122906000 UTC +00:00
}

Post record and associated user record were created in the database:

Post.all # => [<Post:0x00007fd10f824168> {...}]

# User also created in the database
User.all # => [<User:0x00007f91af405b30> {...}]

build_stubbed

build_stubbed imitates creating. It slubs id, created_at, updated_at and user_id attributes. Also it skips all validations and callbacks.

Stubs means that FactoryBot just initialize object and assigns values to the id created_at and updated_at attributes so that it just looks like created. For id it assign integer number 1001 (1001 is just default number what FactoryBot uses to assign to id), for created_at and updated_at assigns current datetime. And for every other record created with build_stubbed is will increment number to be assigned to id by 1. First FactoryBot initialize user record and assign 1001 to id attribute but not save it to the database than it initialize post record and assing 1002 to the id attribute and 1001 to user_id attribute to make association, but also doesn't save record to the database. See example below.

#initialization
post = FactoryBot.build_stubbed(:post)
# call

p post
p post.user
# output
# It looks like persisted instance
#<Post:0x00007fd10f824168> {
   :id => 1002,
   :user_id => 1001,
   :title => "Post title",
   :body => "Post body",
   :created_at => Sat, 18 Jun 2022 05:32:17.122906000 UTC +00:00,
   :updated_at => Sat, 18 Jun 2022 05:32:17.122906000 UTC +00:00
}

#<User:0x00007f8792ed9290> {
  :id => 1001,
  :first_name => "John",
  :last_name => "Joe",
  :created_at => Sat, 18 Jun 2022 05:32:17.122906000 UTC +00:00,
  :updated_at => Sat, 18 Jun 2022 05:32:17.122906000 UTC +00:00
}

Post and user records were not created in the database!!!

# it is not persisted in the database
Post.all # => []

# Association was also just stubbed(initialized) and there are no users in the database.
User.all # => []
Walcoff answered 18/6, 2022 at 5:57 Comment(4)
Thanks for the answer. I'm still confused what it stubs id, created_at, updated_at" and user_id` means, though. How is the output you show for build_stubbed different than what you show for create? I see the id and user_id values are different, but why? Can you explain this in more detail?Shirtwaist
Also, will you show the calls that create each block of output?Shirtwaist
I've updated my answer. Hope it is clearer now;)Walcoff
Thanks for the added detail. I believe it clears up my question. I'll need to work with it directly a bit more to see.Shirtwaist

© 2022 - 2024 — McMap. All rights reserved.