FactoryGirl vs. Bare Domain Objects

I’ve been doing a fair amount of research into testing and what are the best and fasted way to test. Recently, someone at work brought up the fact that using factories can drastically slow down your test suite. Especially when, like us, you create other factories within factories (ie. I need an advertiser for a campaign, so when I use Factory.build(:campaign), it also does Factory.create(:advertiser)). I tried using Factory.stub (check out this article), but it still would create in the background and I couldn’t change that without wrecking all of our other tests. I decided to start testing with bare domain objects, saving nothing to the database (when possible). Here is a comparison of using FactoryGirl vs. bare domain objects:

FactoryGirl

context '#validate flight dates with FactoryGirl' do
  setup do
    @campaign = FactoryGirl.build(:campaign, id: 1234, flight_start: Date.new(2014,01,28), flight_end: Date.new(2014,01,28))
  end
  
  should 'be valid if campaign has the same flight_start and flight_end' do
    assert_true @campaign.valid?
  end
  
  should 'be invalid if flight_end is before flight_start' do
    @campaign.flight_end = Date.new(2014,01,27)
    assert_false @campaign.valid?
    assert @campaign.errors.full_messages.include?('Flight start must be earlier than campaign flight end date')
  end
end

 

Bare Domain Objects

context '#validate flight dates with Bare Domain Objects' do
  should 'be valid if campaign has the same flight_start and flight_end' do
    campaign = Campaign.new(name: 'UNICORNS!!!', flight_start: Date.new(2014,01,28), flight_end: Date.new(2014,01,28))
    campaign.valid?
    assert_false campaign.errors.full_messages.include?('Flight start must be earlier than campaign flight end date')
  end
  
  should 'be invalid if flight_end is before flight_start' do
    campaign = Campaign.new(name: 'UNICORNS!!!', flight_start: Date.new(2014,01,28), flight_end: Date.new(2014,01,27))
    campaign.valid?
    assert campaign.errors.full_messages.include?('Flight start must be earlier than campaign flight end date')
  end
end

Not so different, right? Takes less time since I’m not writing to the database and the only major difference is that I don’t assert that the object is valid. Instead I check to see if it is adding my error message. This helps simplify tests, even for more complicated objects.