Joel Jackson
Joel Jackson

Reputation: 1070

FactoryGirl not giving useful validation errors

I'm using FactoryGirl for my fixtures and am finding that it's not really producing useful validation errors.

I always get the message for activerecord.errors.models.messages.record_invalid.

Not sure what further details are needed to help diagnose this. This makes it an excruciatingly slow process to track each error down.

Example factory:

Factory.define :partner do |partner|
  partner.sequence(:username){ |n| "amcconnon#{n}" }
  partner.first_name            "Bobby Joe"
  partner.last_name             "Smiley"
  partner.sequence(:email){ |n| "bob{n}@partners.com" }
  partner.phone_number          "5557 5554"
  partner.country_id            75
  partner.password              "password"
  partner.password_confirmation "password"
end

Then Factory(:partner) => "ActiveRecord::RecordInvalid Exception: Looks like something went wrong with these changes"

The actual problem is of course the email sequence doesn't use n properly and there is a unique validation on email. But that's for illustrative purposes.

rails => 3.2.2 factory_girl 2.6.1

Any other deets needed to help diagnose this?

(Note: edited this just to add an easier to read factory)

EDIT:

As per bijan's comment: "What exactly am I trying to do."

Trying to run "rspec spec". I would like when I use a factory like Factory(:partner) in this case for the error message when that fails to contain the same error I would get from Partner.new({blah...}).valid? then looked at the validation failures.

Upvotes: 4

Views: 1586

Answers (2)

kstevens715
kstevens715

Reputation: 760

I'm not sure if this is exactly the same problem you were having, but it's a problem I was having with validation error messages not being very useful and I thought it could be useful to others searching for this problem. Below is what I came up with. This could be modified to give different info too.

include FactoryGirl::Syntax::Methods

# Right after you include Factory Girl's syntax methods, do this:

def create_with_info(*args, &block)
  create_without_info(*args, &block)
rescue => e
  raise unless e.is_a? ActiveRecord::RecordInvalid
  raise $!, "#{e.message} (Class #{e.record.class.name})", $!.backtrace
end
alias_method_chain :create, :info

Then, when you use create :model_name, it will always include the model name in the error message. We had some rather deep dependencies (yes, another problem), and had a validation error like, "name is invalid"... and name was an attribute on a few different models. With this method added, it saves significant debugging time.

Upvotes: 4

Mark Weston
Mark Weston

Reputation: 1163

I think the key point here is that when you're setting up a test you need to make sure that the code you're testing fails at the point that you set the expectation (i.e. when you say "should" in Rspec). The specific problem with testing validations is of course that the validation fails as soon as you try to save the ActiveRecord object; thus the test setup mustn't invoke save.

Specific suggesions:

1) IMO Factory definitions should contain the minimum information required to create a valid object and should change as little as possible. When you want to test validations you can override the specific attribute being tested when you instantiate the new test object.

2) When testing validations, use Factory.build. Factory.build creates the ActiveRecord instance with the specified attributes but doesn't try to save it; this means you get to hold off triggering the validation until you set the expectation in the test.

How about something like this?

it "should fail to validate a crap password" do
  partner_with_crap_password = Factory.build(:partner, :password => "crap password")
  partner_with_crap_password.should_not be_valid
end

Upvotes: 0

Related Questions