2

So this is my first time writing unit tests, and Im incorporating Rspec w/FactoryBot.

My Specs were working just fine with using @ instance variables, However when I use let! the second model fails because the first model was never created.

Spec:

require "rails_helper"

RSpec.describe Note, :type => :model do

  before(:all) do
    let!(:event){ FactoryBot.create(:event) }
    let!(:note){ FactoryBot.create(:note) }
  end

  it "is valid with valid attributes" do
    expect(note).to be_valid
  end

end

Factories:

FactoryBot.define do
  factory :note do
    event_id Event.first.id
    content "This is a sample note"
  end
end


FactoryBot.define do
  factory :event do
    title "Event Factory Test"
    event_date Date.today
    event_time "1:30 PM"
  end
end

As you can see, the note requires a Event id (Which requires the event to be created), but it complains when trying to find Event.first.id which should have been created from the let!).

Any ideas? This "seems" to be similar to how others use let in other rspec tests.

1 Answer 1

3

let and let! do not work if you wrap them in a before block.

require "rails_helper"
RSpec.describe Note, :type => :model do
  let!(:event){ FactoryBot.create(:event) }
  let!(:note){ FactoryBot.create(:note) }
  it "is valid with valid attributes" do
    expect(note).to be_valid
  end
end

Also to setup an association within a factory simply pass the name of the factory:

FactoryBot.define do
  factory :note do
    event # short for association :event
    content "This is a sample note"
  end
end

(If the factory name is the same as the association name, the factory name can be left out.).

You're still thinking about factories wrong though. They should be factories that produce unique testable records. Not a set of fixtures. The way you have defined it the factory would only work if a event has been created. Never hardwire factories!

If you want to get the event later just do:

require "rails_helper"
RSpec.describe Note, :type => :model do
  let!(:note){ FactoryBot.create(:note) }
  it "has an event" do
    expect(note.event).to be_a Event
  end
end
Sign up to request clarification or add additional context in comments.

6 Comments

I am using Database_cleaner currently to wipe out the 2 associated tables each time. However adjusting the let! to not be used in a before block doesn't work either (I used it exactly how you have) and it still is acting like the first Event is never created. I can see in the test logs it's never even attempted to be created.
Edited - your factory definition is wrong. Try running FactoryBot.lint which will test the validity of your records.
So I see the problem. In my factory Event.first.id doesn't actually exist yet....since the Event table is blank. The idea is that Event gets created first but....it's failing to do that. How do I handle this? Since I need Event to be created and be in the database first. Which is what the first Event factory is supposed to be doing...
I ended up fixing it by calling event = FactoryBot.create(:event) and then calling event_id event.id in my note factory. I was able to use let afterward
I don't really know what you´re doing here - but yes the whole point of database cleaner is that is wipes the database between each example (each it block).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.