RSpec未通过“应保存”测试

时间:2018-09-15 15:33:17

标签: ruby-on-rails rspec-rails

Link to Repo

我刚开始测试Rails,所以这可能是一件很小的事情,但是我不知道出了什么问题。因此,我想测试一些模型。现在测试很简单。测试属性的存在并保存是否满足所有验证条件。

我的一个模型Profile belongs_to我的Users模型和passes所有这些测试spec/models/profiles_spec.rb

require 'rails_helper'

RSpec.describe Profile, type: :model do
  context 'validation tests' do
    it 'ensures user_id presence' do
      profile = Profile.new(platform: 0, region: 0, tag: 'GamerTag', sr: 1600).save
      expect(profile).to eq(false)
    end

    it 'ensures platform presence' do
      profile = Profile.new(user_id: 1, region: 0, tag: 'GamerTag', sr: 1600).save
      expect(profile).to eq(false)
    end

    it 'ensures region presence' do
      profile = Profile.new(user_id: 1, platform: 0, tag: 'GamerTag', sr: 1600).save
      expect(profile).to eq(false)
    end

    it 'ensures tag presence' do
      profile = Profile.new(user_id: 1, platform: 0, region: 0, sr: 1600).save
      expect(profile).to eq(false)
    end

    it 'ensures sr presence' do
      profile = Profile.new(user_id: 1, platform: 0, region: 0, tag: 'GamerTag').save
      expect(profile).to eq(false)
    end

    it 'should save successfully' do
      profile = Profile.new(user_id: 1, platform: 0, region: 0, tag: 'GamerTag', sr: 1600).save
      expect(profile).to eq(true)
    end
  end
end

app/models/profile.rb

class Profile < ApplicationRecord
  validates :platform, presence: true
  validates :region, presence: true
  validates :tag, presence: true
  validates :sr, presence:true

  belongs_to :user

  enum platform: [:pc, :xbl, :psn]
  enum region: [:us, :eu]
end

但是,还有其他模型,它们“通过”了所有属性存在验证测试,那里有些问题,因为当我注释掉其属性验证并通过'should save successfully'测试时,它们仍然通过。

最令人困惑的部分?当我运行rails控制台并进行手动测试时,它会返回期望值(true),就像我的Student模型中的belongs_to :profile一样。

所以我真的不知道这是怎么回事。任何想法请把它们扔掉。如果您还需要更多信息,请告诉我。

2 个答案:

答案 0 :(得分:1)

确实,这是缺少相关记录的错误。让我们以教练规范为例:

it 'should save successfully' do
  coach = Coach.new(profile_id: 1, roles: ['tank']).save
  expect(coach).to eq(true)
end

(在我的实验中)这里没有ID为1的个人资料。实际上,根本没有配置文件。因此,此规范失败了,正如预期的那样。

Buuuut,等我们到达个人资料规范时

it 'should save successfully' do
  profile = Profile.new(user_id: 1, platform: 0, region: 0, tag: 'GamerTag', sr: 1600)
  expect(profile).to eq(true)
end

id = 1的用户存在(可能是因为用户规范在此规范之前运行并成功创建了用户记录)。

学习的经验:

    在测试之间
  1. 始终清理/回滚数据库(否​​则将其原始)
  2. 始终以随机顺序运行测试。如您在此线程中所见,规格顺序依赖性可能很难检测。

答案 1 :(得分:0)

首先,您正在以一种非常低效的方式编写测试。如果您不想测试验证,则无需测试save方法的返回值,而只需测试valid?方法的值和errors哈希。

RSpec.describe Profile, type: :model do
  context 'validation tests' do
    it 'ensures user_id presence' do
      profile = Profile.new(platform: 0, region: 0, tag: 'GamerTag', sr: 1600, user_id: nil) #you should be explicit with the user_id value being nil, tests should be explicit, it may seem unnecesary but it makes them easier to read
      expect(profile).to be_invalid #or expect(profile).not_to be_valid
      expect(profile.errors[:user_id]).to be_present #you could test the actual message too, not just the presence on any error
    end
  end
end

该测试实际上仅测试验证,并且还确保user_id字段中存在错误。

通过实际测试,您无法知道实际上是什么导致对象无法保存。它可以是任何东西:另一个验证,返回false的before_save回调,在插入数据库时​​的无效值等等。由于它必须将记录实际写到数据库上,因此它也比较慢,测试valid?是在内存上完成的,这要快得多。

Id'建议您阅读有关FactoryBot的信息,因此您不必在每次测试中都重复Profile.new....

如果您仍想在上次测试中测试save的返回值,则必须知道为什么它没有被保存,您可以使用save!引发一个异常,而不是返回false调试代码,然后您还可以检查profile.errors.full_messages来查看是否存在设置测试时没有考虑的错误。