it-swarm.com.ru

Rails 3.1, RSpec: проверка моделей проверки

Я начал свой путь с TDD в Rails и ​​натолкнулся на небольшую проблему, касающуюся тестов для проверки моделей, которые, похоже, не могут найти решение. Допустим, у меня есть модель пользователя,

class User < ActiveRecord::Base
  validates :username, :presence => true
end

и простой тест

it "should require a username" do
  User.new(:username => "").should_not be_valid
end

Это правильно проверяет проверку присутствия, но что, если я хочу быть более конкретным? Например, тестирование full_messages на объекте ошибок.

it "should require a username" do
  user = User.create(:username => "")
  user.errors[:username].should ~= /can't be blank/
end

Моя обеспокоенность по поводу первоначальной попытки (с использованием should_not be_valid) заключается в том, что RSpec не выдаст описательное сообщение об ошибке. Он просто говорит: "Ожидается ли верный? Вернуть ложь, получил истину". Однако у второго тестового примера есть небольшой недостаток: он использует метод create вместо нового, чтобы получить объект ошибок.

Я хотел бы, чтобы мои тесты были более конкретными о том, что они тестируют, но в то же время не должны касаться базы данных.

Кто-нибудь есть какой-либо вклад?

69
Feech

Сначала я хотел бы сказать, что у вас злое имя.

Во-вторых, ПОЗДРАВЛЯЕМ вас с TOR с ROR. Обещаю, что когда вы начнете, вы не оглянетесь назад.

Простейшим быстрым и грязным решением будет создание новой действительной модели перед каждым из ваших тестов, например:

 before(:each) do
    @user = User.new
    @user.username = "a valid username"
 end

НО я предлагаю вам создать фабрики для всех ваших моделей, которые автоматически сгенерируют для вас действительную модель, а затем вы сможете использовать отдельные атрибуты и посмотреть, соответствует ли ваша проверка. Мне нравится использовать FactoryGirl для этого:

По сути, после настройки тест будет выглядеть примерно так:

it "should have valid factory" do
    FactoryGirl.build(:user).should be_valid
end

it "should require a username" do
    FactoryGirl.build(:user, :username => "").should_not be_valid
end

Ах да, и вот хороший Railscast , который объясняет все это лучше, чем я:

удачи :)


ОБНОВЛЕНИЕ: Начиная с версия 3. синтаксис фабричной девушки изменился. Я изменил свой пример кода, чтобы отразить это.

96
Matthew

Более простой способ проверить валидацию моделей (и намного больше активных записей) - использовать гем типа shoulda или замечательный .

Они позволят провести тестирование следующим образом:

describe User

  it { should validate_presence_of :name }

end
42
nathanvda

Попробуй это:

it "should require a username" do
  user = User.create(:username => "")
  user.valid?
  user.errors.should have_key(:username)
end
16
Winston Kotzan

в новой версии rspec вы должны использовать ожидаемую, а не следует, иначе вы получите предупреждение:

it "should have valid factory" do
    expect(FactoryGirl.build(:user)).to be_valid
end

it "should require a username" do
    expect(FactoryGirl.build(:user, :username => "")).not_to be_valid
end
4
dayudodo

Я традиционно обрабатывал спецификации содержания ошибок в характеристиках функций или запросов. Так, например, у меня есть аналогичная спецификация, которую я приведу ниже:

Пример спецификации функции

before(:each) { visit_order_path }

scenario 'with invalid (empty) description' , :js => :true do

  add_empty_task                                 #this line is defined in my spec_helper

  expect(page).to have_content("can't be blank")

Итак, у меня есть моя спецификация модели, проверяющая, является ли что-то действительным, но затем моя спецификация функции, которая проверяет точный вывод сообщения об ошибке. К вашему сведению, эти технические характеристики требуют Capybara, который можно найти здесь .

0
aceofbassgreg

Как сказал @nathanvda, я бы воспользовался самоцветом Thoughtbot Shoulda Matchers . С этим раскачиванием вы можете написать свой тест следующим образом, чтобы проверить наличие, а также любое пользовательское сообщение об ошибке.

RSpec.describe User do

  describe 'User validations' do
    let(:message) { "I pitty da foo who dont enter a name" }

    it 'validates presence and message' do
     is_expected.to validate_presence_of(:name).
      with_message message
    end

    # shorthand syntax:
    it { is_expected.to validate_presence_of(:name).with_message message }
  end

end
0
LaCroixed

Немного опоздал на вечеринку, но если вы не хотите добавлять совпадения, это должно работать с rspec-Rails и factorybot:

# ./spec/factories/user.rb
FactoryBot.define do
  factory :user do
    sequence(:username) { |n| "user_#{n}" }
  end
end

# ./spec/models/user_spec.rb
describe User, type: :model do
  context 'without a username' do
    let(:user) { create :user, username: nil }

    it "should NOT be valid with a username error" do
      expect(user).not_to be_valid
      expect(user.errors).to have_key(:username)
    end
  end
end
0
marksiemers