Rails 3: Duplicate validation error messages during testing
Asked Answered
I

4

9

I'm getting some weird validation behavior: it's duplicating my validation error messages and I can't figure out what's causing it... it doesn't do this in the rails console.

Here is the validation from my Phone model:

# phone.rb
validates :number, :length => { :minimum => 3 }

My spec:

require 'spec_helper'

describe Phone do
  it "requires a number" do
    user = User.make!
    @p = Phone.new(number:nil,user_id:user.id,type:2)
    @p.valid?
    puts @p.errors.inspect 
    @p.should have(1).error_on(:number)
  end

My test results:

# rspec and machinist
#<ActiveModel::Errors:0x000000036f1258 @base=#<Phone id: nil, user_id: 614, kind: nil, number: nil, created_at: nil, updated_at: nil>, @messages={:number=>["is too short (minimum is 3 characters)", "is too short (minimum is 3 characters)"]}>
F

Failures:

  1) Phone requires a number
     Failure/Error: @p.should have(1).error_on(:number)
       expected 1 error on :number, got 2
     # ./spec/models/phone_spec.rb:11:in `block (2 levels) in <top (required)>'

Finished in 0.50988 seconds
1 example, 1 failure

As you can see, I'm getting "is too short (minimum is 3 characters)" twice... It's also /only/ happening during testing. Any ideas?

Thanks!

Inviting answered 23/9, 2011 at 19:31 Comment(4)
what do your association definitions look like and do you use validates_associated?Bartels
In Phone, it has_one :user, and in User, it has_many :phones. I started using valid_attribute gem to test my validatons, and that is much nicer than this method.Inviting
nope... not yet. Hasn't been an issue since I stopped testing that way.Inviting
Stab in the dark -- what if you change describe Phone do to describe 'Phone' do ?Clavichord
W
9

The problem is in the line:

Dir["#{Rails.root}/app/**/*.rb"].each { |f| load f }

in the spec_helper.rb file, in the Spork.each_run block

If you change the method 'load' to 'require', it fixes the problem.

Or if you have a recent enough version of Spork, you can remove the line altogether. I am pretty sure the error is caused when someone is installing a newer version Spork(0.9.0+) with old instructions, because the line:

Dir["#{Rails.root}/app/**/*.rb"].each { |f| load f }

doesn't even has to be stated explicitly in the spec_helper.rb file anymore. If it is then when the load method is used in the spec_helper.rb file, it reloads the files specified , most likely the cause of the strange RSpec duplicate validations errors.

Werby answered 8/8, 2012 at 20:36 Comment(1)
A lot of people voted for this one, I'm going to mark it as answered (I haven't used spork in a long time).Inviting
C
1

I encountered a similar issue of duplicate error messages, but it seemed to stem from my use of a different directory structure than the standard, e.g.:

- app
  \- models_one
  |- models_two
  |- models_three

My load/require call in the Spork.each_run block looked like this:

Dir["#{Rails.root}/app/models_*/*.rb"].each { |f| load f }

I removed this and replaced it with these:

ActiveSupport::Dependencies.clear
ActiveRecord::Base.instantiate_observers

And there were no more duplicate error messages.

I was helped by this post: http://adams.co.tt/blog/2012/04/12/duplicate-active-model-validation-errors/ in which the author says it's a 1.8.7-specific problem which involves requiring different paths which resolve to the same file, but I am using 1.9.3 so it may not be related.

Cleareyed answered 17/2, 2013 at 12:22 Comment(0)
H
0

I'm not sure if this is going to solve your problem, but rspec is very quirky if you don't follow rspec convention. Try some more idiomatic rspec like the following:

require 'spec_helper'

describe Phone do
  context :validations do
    let(:user) { double(:user) }
    subject { Phone.new(number:nil,user_id:user.id,type:2) }

    before do
      subject.valid?
    end

    it 'should have a minimum length of 3' do
      subject.should have(1).error_on(:number)
    end
  end
end

I'd also like to suggest that you shouldn't unit test Rails' built in validations; they are already tested in Rails itself. Specifically, your length validation is tested in activemodel/test/cases/validations/length_validation_test.rb. The behavior of the validations should be covered in your integration tests.

I hope that's helpful.

Heindrick answered 13/3, 2012 at 21:8 Comment(1)
Cool, thanks for this. The point (for me) for unit testing validations is to very quickly whitelist/blacklist things you care/don't care about (integration tests are not as fast as unit tests!), and the valid_attribute gem works great for this... but, for reference, the above example was taken directly from the rspec website's example on model validation: relishapp.com/rspec/rspec-rails/v/2-8/docs/model-specs/…Inviting
S
0

I'm having the same problem (using rspec & spork).

I suspect it's something to do with the model being required twice, causing validations to run twice.

If you explicity require 'phone' at the top of your spec, it seems to fix it.

But I'd really like to know what's causing the problem...

Springfield answered 25/4, 2012 at 11:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.