RSpec 未通过 'should save' 测试

RSpec not passing 'should save' test

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

但是还有我的其他模型,其中 "pass" 所有属性存在验证测试,其中有一些错误,因为当我注释掉它们的属性验证并且未通过 'should save successfully' 时它们仍然通过测试。

最令人困惑的部分?当我 运行 rails 控制台并手动测试它时 returns 预期值 (true),就像我的 Student 模型 belongs_to :profile.

所以我真的不知道这里发生了什么。任何想法请扔掉。如果大家需要更多信息,请告诉我。

首先,您正在以一种非常低效的方式编写测试。如果您不想测试验证,那么您不需要测试 save 方法 return 值,而是测试 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 字段中存在错误。

通过实际测试,您无法知道实际上是什么阻止了对象的保存。它可以是任何东西:另一个验证、before_save 回调 returning false、插入数据库时​​的无效值,任何东西。它也更慢,因为它必须实际将记录写入数据库,测试 valid? 是在内存上完成的,内存要快得多。

我建议您阅读有关 FactoryBot 的内容,这样您就不必在每次测试中重复 Profile.new....

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

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

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. 始终 clean/rollback 测试之间的数据库(或以其他方式使其保持原始状态)
  2. 始终 运行 以随机顺序进行测试。正如您在此线程中看到的那样,规范顺序依赖性可能很难检测到。