There are times in your tests when you need to create multiple instances of the same type
of object. FactoryBot1 provides create_list
for just these
sorts of scenarios. It’s typically sufficient to create two records in these
cases, but create_list
leaves open the possibility that you could
unintentionally create many more records.
Consider, for example, testing a feature that pages in additional records on demand. You would likely want to use something like Kaminari to expose the paging functionality. We did just this on a recent project.
scenario 'user can page in additional records' do
posts = create_list(:post, Post.default_per_page + 1)
click_button "Load More"
expect(page).to have_content(posts.first.body)
expect(page).to have_content(posts.last.body)
end
The trouble is that Kaminari defaults the default_per_page
value to 25. This
test will create 26 records in your database. Seems a bit much, no? The simplest
way to solve this is to stub the Post.default_per_page
method in the test, but
you will have to remember to do this in every place you test paging. Not so bad
if you’re only paging Post
, but what about Comment
, Author
, etc?
Sane Kaminari Defaults in Test
The first step we took towards solving this was to introduce an initializer that defaults the Kaminari page size to 1 record in the test environment.
Kaminari.configure do |config|
if Rails.env.test?
config.default_per_page = 1
end
end
This works great until someone comes along and overrides the default page size
on Post
with paginates_per(20)
. Now you’re back to creating 21 records in
your test or having to remember to stub the default_per_page
method on models
that override the Kaminari default.
A Safety Net: Let’s Patch Factory Bot
The application we’re working on has a lot of paging. I half-jokingly
suggested we override create_list
to prevent gigantic list creation. When
the idea wasn’t met with immediate guffaws, I went to work. I added the
following to our FactoryBot configuration that is required from
spec_helper
:
require 'factory_bot_rails'
module FactoryBot
module Syntax
module Methods
alias_method :original_create_list, :create_list
def create_list(name, amount, *traits_and_overrides, &block)
if amount > 2
raise ArgumentError, "You asked to create #{amount} records. Don't do that."
end
original_create_list(name, amount, *traits_and_overrides, &block)
end
end
end
end
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end
Calls to create_list
will now raise if you attempt to create more than two
records. In the case of our paging example, this signals that we forgot to stub
the defaults_per_page
method. If you have a legitimate need to create more
than two records, you can call original_create_list
.
Interestingly, this change surfaced a number of non-paging tests that were creating three records where even just one would do.
Project name history can be found here.
-
Looking for FactoryGirl? The library was renamed in 2017. ↩