4

I want to use FactoryGirl to build in-memory stubs of models, then have all ActiveRecord queries run against only those. For example:

# Assume we start with an empty database, a Foo model, 
# and a Foo factory definition.

#foo_spec.rb
stubbed_foo = FactoryGirl.build_stubbed(:foo)

# Elsewhere, deep in the guts of application
Foo.first() # Ideally would return the stubbed_foo we created
            # in the test. Currently this returns nil.

The solution might be to use an in-memory database. But is the above scenario possible?

Kyle McVay
  • 488
  • 3
  • 13
  • If you don't have any tables, then there's no schema for models to follow, so your stubbed model could behave like any object without having to match with the actual schema that will exist in production. This would probably be a bad idea. Why are you trying to bypass ActiveRecord in this way? – Robin Daugherty Feb 04 '17 at 18:31
  • You could use fixtures instead of factory girl – trueinViso Feb 04 '17 at 18:56
  • @trueinViso I don't think fixtures would solve my problem, as the Foo class would still go to the database when calling `first()` or any other query method. – Kyle McVay Feb 05 '17 at 20:20

1 Answers1

1

If your reason for avoiding the database, is to speed up your tests, then there are better ways.

Use FactoryGirl.build as much as possible instead of create. This works as long as the record won't be fetched from the database by your code. This works well for unit tests with well-structured code. (For example, it helps to use Service Objects and unit test them independently.

For tests that actually need to read from the database (as in your Foo.first example call), you can use FactoryGirl.create and use transactional fixtures. This creates a database transaction at the beginning of each test example, and then rolls back the transaction at the end of the example. This can cause problems when you use callbacks in your ActiveRecord models such as after_commit.

If you use after_commit or other callbacks in your models that require the database transaction to close (or you use explicit transactions in your code), I recommend setting up DatabaseCleaner. Here's an example of to configure and use it: https://gist.github.com/RobinDaugherty/9f4e5f782d9fdbe191a23de30ad8b539

Robin Daugherty
  • 7,115
  • 4
  • 45
  • 59
  • Yes, my motivation is keeping the test suite speedy. I'm using `FactoryGirl.build` and `FactoryGirl.build_stubbed` as much as possible, but I was looking for a way to eliminate the database dependency entirely. I don't think transactional fixtures will accomplish what I want either. This might be a case of premature optimization on my part, but I just wanted to make sure it wasn't possible before I start writing tests with database interaction. – Kyle McVay Feb 05 '17 at 20:40
  • I doubt that you will see any substantial increase in speed going from `FactoryGirl.build` to using stubs. But you will definitely lose quality in your tests, since using a model factory ensures that model behavior is correct. I wouldn't recommend it. – Robin Daugherty Feb 06 '17 at 05:11