Factory girl rspec and authlogic

I am trying some simple test using the above items. Using the
Factory.create(…) gives Active Record errors and not the failure of
the test. Change it to u = Factory.build(…) then u.save, I do not
get the Active record error but the proper test failure message.

it ‘requires email’ do
lambda do
u = Factory.create(:valid_user, {:email => nil})
#u.save
u.errors.on(:email).should_not be_nil
end.should_not change(User, :count)
end

returns:
ActiveRecord::RecordInvalid in ‘User requires email’
Validation failed: Email is too short (minimum is 6 characters), Email
should look like an email address.
./spec/models/user_spec.rb:34:
./spec/models/user_spec.rb:33:

However:
it ‘requires email’ do
lambda do
u = Factory.build(:valid_user, {:email => nil})
u.save
u.errors.on(:email).should be_nil
end.should change(User, :count)
fails properly with
‘User requires email’ FAILED
expected nil, got [“is too short (minimum is 6 characters)”, “should
look like an email address.”]
./spec/models/user_spec.rb:36:
./spec/models/user_spec.rb:33:

It does not matter whether the first test above is above is set up as
a failing or passing test I get the same results, ActiveRecord errors
instead of Rspec messages.

I am not sure if this is a FactoryGirl issue or Rspec issue, or me
screwing up.

Thanks

On Sat, Oct 3, 2009 at 8:41 PM, Don F. [email protected] wrote:

I am trying some simple test using the above items. Using the
Factory.create(…) gives Active Record errors and not the failure of
the test. Change it to u = Factory.build(…) then u.save, I do not
get the Active record error but the proper test failure message.

I don’t think you have a problem with Factory Girl or with RSpec.
Both are working as intended. Factory Girl’s ‘create’ method is
calling ‘save!’ instead of ‘save’ – the difference being that ‘save!’
throws an exception instead of returning false when validations fail.
That’s exactly what you’re seeing. And it’s reasonable, because if
you ask it to create a record, it assumes that you want a record,
and that an inability to make one is unexpected. The ‘build’ method
is intended exactly for things like validation testing.

There are a few better ways you can test for this than what you’re
doing. One is to try ‘create’ and test for the exception it throws:

it ‘requires email’ do
lambda { Factory.create(:valid_user, :email => nil) }.should
raise_error(ActiveRecord::RecordInvalid)
end

…This would work, but it’s clunky. I don’t like lambdas if I can
avoid them. I would probably do it like this instead:

it ‘requires email’ do
u = Factory.build(:valid_user)
u.email = nil
u.should_not be_valid
end

Assuming another test where a :valid_user proved to actually be
valid, this is entire and sufficient.

If you consider it important to know what the error messages are well
(I generally don’t), you could also do:

it ‘requires email’ do
u = Factory.build(:valid_user)
u.email = nil
u.save.should be_false
u.should have(2).errors.on(“email”)
u.errors.on(“email”).should include(“is too short (minimum is 6
characters)”)
u.errors.on(“email”).should include(“should look like an email
address.”)
end

In practice, even if I did care about all of that, I’d split them out
into separate examples, because I subscribe to the philosophy that a
good example should have at most one expectation. Four “shoulds” is
three too many. But that’s a subtle distinction, and I wanted to be
brief here.

The one thing I wouldn’t do is what you’re doing in both code
blocks, which is to wrap an expectation inside a lambda and then put
another expectation outside it. Checking that the record count did
not change is really unnecessary. The save failed. That’s
sufficient.

(By the way, if I screwed up any of the syntax with Factory Girl here,
my apologies. I don’t use it; I use Machinist. That’s another one of
those personal preference things, though.)


Have Fun,
Steve E. ([email protected])
ESCAPE POD - The Science Fiction Podcast Magazine
http://www.escapepod.org