ruby-on-rails - run - rspec rails
Rails 3.1, RSpec: pruebas de validaciones del modelo (7)
Como dijo @nathanvda, aprovecharía la gema de Thoughtda Shchers de Thoughtbot . Con ese balanceo, puede escribir su prueba de la siguiente manera para verificar su presencia, así como también cualquier mensaje de error personalizado.
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
Empecé mi viaje con TDD en Rails y me encontré con un pequeño problema relacionado con las pruebas de validación de modelos que parece que no puedo encontrar una solución. Digamos que tengo un modelo de usuario
class User < ActiveRecord::Base
validates :username, :presence => true
end
y una prueba simple
it "should require a username" do
User.new(:username => "").should_not be_valid
end
Esto prueba correctamente la validación de presencia, pero ¿qué ocurre si quiero ser más específico? Por ejemplo, probar full_messages en el objeto de error ...
it "should require a username" do
user = User.create(:username => "")
user.errors[:username].should ~= /can''t be blank/
end
Mi preocupación sobre el intento inicial (utilizando should_not be_valid) es que RSpec no producirá un mensaje de error descriptivo. Simplemente dice: "¿Se espera que sea válido? Devolver falso, hacerse realidad". Sin embargo, el segundo ejemplo de prueba tiene un inconveniente menor: utiliza el método create en lugar del nuevo método para obtener el objeto de error.
Me gustaría que mis pruebas sean más específicas sobre lo que están probando, pero al mismo tiempo no tienen que tocar una base de datos.
Alguien tiene alguna entrada?
Primero, me gustaría decir que tienes un nombre malvado.
Segundo, FELICIDADES por esforzarse en TDD con ROR. Prometo que una vez que empiece no mirará hacia atrás.
La solución rápida y sucia más simple será generar un nuevo modelo válido antes de cada una de sus pruebas como esta:
before(:each) do
@user = User.new
@user.username = "a valid username"
end
PERO lo que sugiero es que configure fábricas para todos sus modelos que generarán automáticamente un modelo válido para usted y luego podrá mezclar los atributos individuales y ver si su validación. Me gusta usar FactoryGirl para esto:
Básicamente, una vez que te preparas, tu prueba se vería así:
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
Ah, sí, y aquí hay un buen railscast que lo explica todo mejor que yo:
buena suerte :)
ACTUALIZACIÓN: A partir de la versión 3.0, la sintaxis de fábrica ha cambiado. He modificado mi código de muestra para reflejar esto.
Prueba esto:
it "should require a username" do
user = User.create(:username => "")
user.valid?
user.errors.should have_key(:username)
end
Tradicionalmente he manejado las especificaciones de contenido de error en características o especificaciones de solicitud. Entonces, por ejemplo, tengo una especificación similar que voy a condensar a continuación:
Ejemplo de especificación de funciones
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")
Entonces, tengo mi especificación de modelo probando si algo es válido, pero luego mi especificación de función que prueba la salida exacta del mensaje de error. FYI, estas características requieren Capibara, que se puede encontrar here .
Un poco tarde para la fiesta aquí, pero si no quiere agregar adaptadores de debería, esto debería funcionar con rspec-rails y 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
Una forma más fácil de probar las validaciones del modelo (y mucho más de registro activo) es usar una gema como shoulda o remarkable .
Permitirán la prueba de la siguiente manera:
describe User
it { should validate_presence_of :name }
end
en la nueva versión de rspec, debe usar expect en su lugar debería, de lo contrario recibirá una advertencia:
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