Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rspec/FactoryGirl: clean database state

I am new to Rspec and Factory girl and would like my test to run on a specific database state. I understand I can get Factory girl to create these records, and the objects will be destroyed after the test run, but what happens if I have data in the database.

For example: I want my test to run when there are 3 records in the database that I created through Factory Girl. However, I currently already have 1 model record in the database, and I don't want to delete it just for the test. Having that 1 model in there ruins my test.

Database Content

[#<Leaderboard id: 1, score: 500, name: "Trudy">]

leaderboard_spec.rb

require 'spec_helper'

describe Rom::Leaderboard do

    describe "poll leaderboard" do
        it "should say 'Successful Run' when it returns" do
            FactoryGirl.create(:leaderboard, score: 400, name: "Alice")
            FactoryGirl.create(:leaderboard, score: 300, name: "Bob")
            FactoryGirl.create(:leaderboard, score: 200, name: "John")
            Leaderboard.highest_scorer.name.should == "Alice"
        end
    end

end

Now my test will fail because it will incorrectly assume that Trudy is the highest scorer, since the test have run in an incorrect state.

Does factory girl offer anyway to delete records from the database then rollback this delete? Similar to how it creates records in the database and rollsback

like image 469
user2158382 Avatar asked Jan 24 '14 02:01

user2158382


People also ask

Does RSpec clean database?

I use the database_cleaner gem to scrub my test database before each test runs, ensuring a clean slate and stable baseline every time. By default, RSpec will actually do this for you, running every test with a database transaction and then rolling back that transaction after it finishes.

What is FactoryBot in RSpec?

Factory Bot is a helper for writing factories for Ruby tests. It was previously known as Factory Girl. For older versions, use FactoryGirl instead of FactoryBot . Factory Bot documentation (rubydoc.info) Getting started (github.com)

What is 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.

What does factory bot do?

Factory Bot, originally known as Factory Girl, is a software library for the Ruby programming language that provides factory methods to create test fixtures for automated software testing.


2 Answers

Its popular to use the database_cleaner gem. You can find it here:

https://github.com/bmabey/database_cleaner

The documentation recommends the following configuration for rspec:

RSpec.configure do |config|

  config.before(:suite) do
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

end

This will you make sure you have a clean database for each test.

like image 111
jklina Avatar answered Oct 02 '22 13:10

jklina


To answer your rollback question as directly as possible: no there isn't a way to rollback a delete within a test.

Following test conventions your goal usually is to start with a clean slate, and use factory_girl to efficiently build the scenario in the database you need to test for.

You can accomplish what you want by, for instance, adding a this to your leaderboards.rb factory file:

factory :trudy do
  id 1
  score 500
  name "Trudy"
end

Or you could create a simple helper function in your test file that regenerates that record when its needed for tests:

def create_trudy
  FactoryGirl.create :leaderboard,
    id: 1,
    score: 500,
    name: "Trudy"
  end
end

Or you could place all this in a before(:suite) within a describe block, like so:

describe "with a leaderboard record existing" do
  before(:each) do
    FactoryGirl.create :leaderboard, id: 1, score: 500, name: "Trudy"
  end
  # Tests with an initial leaderboard record
end
describe "with no leaderboard records initially" do
  # Your test above would go here
end

In this final suggestion, your tests become very descriptive and when viewing the output, you will know exactly what state your database was in at the beginning of each test.

like image 41
Nick Gronow Avatar answered Oct 02 '22 14:10

Nick Gronow