73 votes

Rails 3.1, RSpec : tester les validations de modèles

J'ai commencé mon voyage avec TDD dans Rails et j'ai rencontré un petit problème concernant les tests pour les validations de modèles que je n'arrive pas à trouver une solution. Disons que j'ai un modèle User,

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

et un simple test

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

Cela permet de tester correctement la validation de la présence, mais que faire si je veux être plus précis ? Par exemple, tester full_messages sur l'objet errors

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

Ce qui me préoccupe dans la première tentative (en utilisant should_not be_valid), c'est que RSpec ne produira pas de message d'erreur descriptif. Il dit simplement "expected valid ? to return false, got true". Cependant, le deuxième exemple de test présente un inconvénient mineur : il utilise la méthode create au lieu de la méthode new pour accéder à l'objet errors.

J'aimerais que mes tests soient plus spécifiques sur ce qu'ils testent, mais qu'en même temps ils n'aient pas à toucher à une base de données.

Quelqu'un a-t-il des commentaires à faire ?

0voto

mdkirby Points 63

Je suis un peu en retard, mais si vous ne voulez pas ajouter de matchers shoulda, cela devrait fonctionner avec rspec-rails et 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

0voto

aceofbassgreg Points 908

J'ai toujours traité les spécifications relatives au contenu des erreurs dans les spécifications des fonctionnalités ou des demandes. Ainsi, par exemple, j'ai une spécification similaire que je vais condenser ci-dessous :

Exemple de cahier des charges

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")

J'ai donc une spécification de modèle qui teste si quelque chose est valide, mais aussi une spécification de fonctionnalité qui teste la sortie exacte du message d'erreur. Pour information, ces spécifications nécessitent l'utilisation de Capybara qui peut être trouvé à l'adresse suivante aquí .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X