RSpec не проходит тест «следует сохранить» - PullRequest
0 голосов
/ 15 сентября 2018

Ссылка на репо

Я новичок в тестировании Rails, так что это, вероятно, очень маленькая вещь, но я не могу понять, что не так. Итак, у меня есть несколько моделей, которые я бы хотел протестировать. Прямо сейчас тесты просты; проверка наличия атрибутов и сохранение, если все проверки выполнены.

Одна из моих моделей Profile belongs_to моя Users модель и проходит все эти тесты 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 голосов
/ 15 сентября 2018

Действительно, это ошибка пропущенных связанных записей. Давайте возьмем спецификацию тренера, например:

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

пользователь с идентификатором = 1 существует существует (вероятно, потому что спецификация пользователя была запущена до этого и успешно создала запись пользователя).

Уроки для изучения:

  1. Всегда очистить / откатить базу данных между тестами (или иным образом сделать ее нетронутой)
  2. Всегда запускать тесты в случайном порядке. Как вы можете видеть в этой теме, очень сложно обнаружить зависимость от порядка спецификаций.
0 голосов
/ 15 сентября 2018

Прежде всего, вы пишете тесты действительно неэффективным способом. Если вы не хотите проверять валидации, вам не нужно тестировать возвращаемое значение метода 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.

С вашим настоящим тестом вы не можете знать, что на самом деле мешает сохранить объект. Это может быть что угодно: другая проверка, обратный вызов before_save, возвращающий false, недопустимое значение при вставке в базу данных, что угодно. Он также медленнее, поскольку фактически должен записывать запись в базу данных, тестирование valid? выполняется в памяти, что намного быстрее.

Я бы рекомендовал вам прочитать о FactoryBot, чтобы вам не приходилось повторять Profile.new.... при каждом тесте.

Если вы все еще хотите проверить возвращаемое значение save в последнем тесте, вы должны знать, ПОЧЕМУ оно не сохраняется, вы можете использовать save!, который вызывает исключение вместо возврата false для отладки вашего кода, и вы также можете проверить profile.errors.full_messages на наличие ошибок, которые вы не учитывали при настройке теста.

...