简体   繁体   中英

How to test a validation with conditional in a Model Rails

I was wondering if I had to test a model with a particular condidion. Let's say that I have a User model who needs a country validation. This country validations has been set up more than 12 months after the creation of the platform so, we have some User who don't have validate country (or don't have any country)

Here's why we have a allow_nil: true .

But we got a problem. One of this User, needs to reset his/her password but like the country is not a valid one according, he/she can't reset his/her password.

So here's what I found to solve this issue:

unless: -> { reset_password_token.present? }

class User < Applicationrecord

VALID_COUNTRY_NAMES = ['Afghanistan', 'Åland', 'Albania', 'Algeria', 'American Samoa', 'Andorra', 'Angola', 'Anguilla', 'Antarctica', 'Antigua and Barbuda'....]

validates :country, allow_nil: true, inclusion: { in: VALID_COUNTRY_NAMES }, unless: -> { reset_password_token.present? }
end

Question: How do I test this specific condition (user with un unvalid country who want to reset password?

I kind of block on that question and I have to admit that testing is not easy for me.

SOLUTION

Thanks to @AbM I could resolve it with the following test:

it 'allows existing user to reset password' do
  user = build(:user, country: 'invalid', reset_password_token: 'some_value')
  expect(user.reset_password_token).to eq('some_value')
  expect(user).to be_valid
end

I still don't know why I've struggle so much for a such easy test !

Don't use the to be_valid matcher. When it fails it tells you nothing about the actual behavior under test.

A real problem is also that you're testing every single validation at once on your model so it really says a lot more about your factories/fixtures then your valiations.

Instead just setup the model with valid or invalid data (arrange) and call #valid? to trigger the validations (act) and then write expectations based on the ActiveModel::Errors API provided by rails (assert).

context "when the user does not have a password reset token" do
  let(:user) do
    User.new(
      country: 'Lovely'
    )
  end
  it "does not allow an invalid country" do
    user.valid?
    expect(user.errors.details[:country]).to include { error: :inclusion, value: "Lovely" }
  end
end

context "when the user has a password reset token" do
  let(:user) do
    User.new(
      country: 'Lovely',
      reset_password_token: 'abcdefg'
    )
  end

  it "allows an invalid country" do
    user.valid?
    expect(user.errors.details[:country]).to_not include { error: :inclusion, value: "Lovely" }
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM