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 на объекте errors..
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, получил true."Однако второй тестовый пример имеет небольшой недостаток: он использует метод create вместо нового метода для получения объекта errors.
Я хотел бы, чтобы мои тесты были более конкретными о том, что они тестируют, но в то же время не должны касаться базы данных.
У кого-нибудь есть вход?
7 ответов:
во-первых, я хотел бы сказать, что у вас есть злое имя.
во-вторых, поздравляю вас с вашим стремлением в 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 это объясняет все лучше, чем я:
удачи :)
обновление: начиная с версия 3.0 синтаксис для factory girl изменился. Я изменил свой пример кода, чтобы отражать это.
более простой способ проверить валидацию модели (и многое другое из active-record) - использовать драгоценный камень, такой как должен был или замечательный.
они позволят тесту следующим образом:
describe User it { should validate_presence_of :name } end
попробуйте это:
it "should require a username" do user = User.create(:username => "") user.valid? user.errors.should have_key(:username) end
в новой версии для 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
Я традиционно обрабатывал спецификации содержимого ошибок в спецификациях функций или запросов. Так, например, у меня есть аналогичная спецификация, которую я буду конденсировать ниже:
Пример Спецификации Функции
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")
Итак, у меня есть моя спецификация модели, проверяющая, действительно ли что-то действительно, но затем моя характеристика, которая проверяет точный вывод сообщения об ошибке. К вашему сведению, эти характеристики требуют капибары, которые можно найти здесь.
Как @nathanvda сказал, я хотел бы воспользоваться
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
немного поздно на вечеринку здесь, но если вы не хотите добавлять shoulda matchers, это должно работать с 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