tests run rails matchers how bot ruby-on-rails ruby-on-rails-3 rspec rspec2 rspec-rails

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