Rails 3.1, RSpec: проверка валидации модели
Я начал свое путешествие с TDD в Rails и столкнулся с небольшой проблемой, касающейся тестов для проверки модели, которые я, похоже, не могу найти. Скажем, у меня есть модель User,
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 не выдаст описательного сообщения об ошибке. Он просто говорит: "Ожидаемый допустимый?", Чтобы вернуть false, получил истинное значение ". Однако второй тестовый пример имеет незначительный недостаток: он использует метод create вместо нового метода для доступа к объекту ошибок.
Я бы хотел, чтобы мои тесты были более конкретными в отношении того, что они тестируют, но в то же время не нужно касаться базы данных.
У кого-нибудь есть вход?
Ответы
Ответ 1
Сначала я хотел бы сказать, что у вас есть злобное имя.
Во-вторых, ПОЗДРАВЛЯЕМ, что вы пытаетесь в TDD с 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, который объясняет все это лучше меня:
удачи:)
UPDATE: с версия 3.0 синтаксис для factory изменился. Я изменил свой пример кода, чтобы отразить это.
Ответ 2
Более простой способ проверки валидации модели (и многое другое из активной записи) заключается в использовании драгоценного камня, такого как shoulda или remarkable.
Они разрешат тест следующим образом:
describe User
it { should validate_presence_of :name }
end
Ответ 3
Попробуйте следующее:
it "should require a username" do
user = User.create(:username => "")
user.valid?
user.errors.should have_key(:username)
end
Ответ 4
в новой версии rspec, вы должны использовать expect вместо этого, иначе вы получите предупреждение:
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
Ответ 5
Я традиционно обрабатывал спецификации содержимого ошибок в спецификациях функций или запросов. Так, например, у меня есть аналогичная спецификация, которую я буду конденсировать ниже:
Пример спецификации функции
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")
Итак, у меня есть моя модель, проверяющая, действительно ли что-то, но затем моя спецификация функций, которая проверяет точный вывод сообщения об ошибке. FYI, эти особенности спецификации требуют Capybara, которые можно найти здесь.
Ответ 6
Как @nathanvda сказал, я бы воспользовался Thoughtbot Assa Matches. С этим покачиванием вы можете написать свой тест следующим образом, чтобы проверить наличие, а также любое сообщение об ошибке.
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