Rspec, shoulda, validate_uniqueness_of with scope and wrong error message
Asked Answered
A

6

15

I have following Rspec test:

describe Productlimit do

  before(:each) do 
    @productlimit = Factory.create(:productlimit, :user => Factory.create(:user))
  end

  subject { @productlimit }

  ...

  it { should validate_uniqueness_of(:price_cents).scoped_to(:direction_down, :currency, :market_id, :user_id) }
  ...
end

But I get following confusing error:

1) Productlimit 
     Failure/Error: it { should validate_uniqueness_of(:price_cents).scoped_to(:direction_down, :currency, :market_id, :user_id) }
       Expected errors to include "has already been taken" when price_cents is set to 9530, got errors: ["direction_down has already been taken (false)"]

Can you help me? I don't understand why this isn't working, because the error message seems to be correct?

EDIT:

This happens too in other situations as well:

# product_spec.rb
...
it { should validate_numericality_of(:price).with_message("price_cents must be greater than 0 (0)") }  

# rake spec:models
Failure/Error: it { should validate_numericality_of(:price).with_message("price_cents must be greater than 0 (0)") }
   Expected errors to include "price_cents must be greater than 0 (0)" when price is set to "abcd", got errors: ["price_cents must be greater than 0 (0)"]
Afflux answered 3/7, 2011 at 16:35 Comment(8)
what versions of shoulda/rspec are you using?Bluestocking
I have shoulda-matchers (1.0.0.beta2), but i tried it with the current 'shoulda' gem as well..Afflux
it seems to me that you are testing something that rails should already be testing. if you have validate_numericality of in your model, why also call it in your tests? that's unnecessary duplicationWahkuna
if the validation is part of the specification of the behavior, he should be testing it.Hypophosphate
Does the Factory.create call succeed by itself? You might try isolating this test by running it on a Productlist.new(:price_cents => ...) object.Coelom
The factory creation works quite well, no errors or warnings...Afflux
Do you mind adding the Productlimit model code as well, in the question?Menses
Two things I'd like to point out: (1) Factory.create hits the database, use .build instead so it just creates the object without the record. You can still check validations on non-stored records. (2) Move the factory to a let, so that it's lazy evaluated in the scope of the description/context block.Saltish
S
12

To check validate_uniqueness_of(:field) but for this you should at lease one record in database to check uniquness constrain. Here is....

before do
  @country = FactoryGirl.create(:country, :id =>"a0000007-0000-0000-0000-000000000009",:currency_id => "a0000006-0000-0000-0000-000000000004",:merchant_id => "a0000001-0000-0000-0000-000000000002",:country_code => 'CAN', :name => 'Canada')
end

To validate uniqueness

it { should validate_uniqueness_of(:country_code)}

It will work out try it out.

Sponson answered 23/11, 2011 at 11:18 Comment(0)
T
3

To add to what Riche has said about uniqueness validation on :direction_down, I would suspect the way your ProductLimit factory generates values for :direction_down. It might not always be generating unique values for all attributes which have the uniqueness validation on them.

Also, one issue I have faced with uniqueness validation is the first object ( the subject in your case) thats is created before the validation check should not have any conflicting values with ones the factory "randomly" generates. To illustrate with a trivial example,

Factory(:product_limit, :direction_down => "abc")
it { should validate_uniqueness_of(:price_cents).scoped_to(:direction_down) }

has the potential to fail wrongly, in case the object constructed by the shoulda matcher ends with direction_down set to "abc" when there is a uniqueness validation on :direction_down.

Torero answered 15/9, 2011 at 8:10 Comment(0)
C
2

Do you have the database_cleaner settings in the sepc_helper? if not then add

gem "database_cleaner"

in spec_helper.rb add the following in the RSpec.configure block

 config.use_transactional_fixtures = false

 config.before(:suite) do
   DatabaseCleaner.strategy = :truncation
 end

 config.before(:each) do
   DatabaseCleaner.start
 end

 config.after(:each) do
   DatabaseCleaner.clean
 end

Also can you post the Factory code? just to have a clearer picture.

I hope this helps.

Also check if there is any uniqueness validation on :direction_down attribute.

Clement answered 21/7, 2011 at 9:23 Comment(1)
Thanks for your answer, ich removed now this specific test and test it myself manually... Tried your solution, but didnt work either..Afflux
S
0

Try to remove test/fixtures/* and try to manually create object before testing uniqueness (not using Factory). Also, have you tried:

    class MyModelTest < ActiveSupport::TestCase 
Stargell answered 13/7, 2011 at 13:48 Comment(1)
I test with rspec (no test folder at all) and tried it to save my objects manually, which works. But the test doesnt work.Afflux
V
0

The error isn't correct for the matcher because it's complaining about the uniqueness of :direction_down when you asked it to test that the uniqueness of :price_cents was valid.

Does the code for your model include a validates_uniqueness_of :direction_down? If so, that would explain the message.

Velleman answered 19/8, 2011 at 4:25 Comment(0)
R
0

The first case (with validate_uniquess_of) happened to me after an unexpected crash. A simple rake db:test:prepare fixed it.

Ranitta answered 7/3, 2013 at 19:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.