Verwenden von shoulda, um rspec-Tests für Rails-Modelle umzugestalten

Nach dem Lernen überShoulda-Matcher durch antworteneine weitere StackOverflow-Frage zu Attributzugriffstests (und ich fand sie ziemlich großartig), beschloss ich, die Modelltests, in denen ich gearbeitet habe, zu überarbeitenDas Rails Tutorial um sie noch prägnanter und gründlicher zu gestalten. Ich habe mich dabei von der Dokumentation der Module inspirieren lassenShoulda::Matchers::ActiveRecord undShoulda::Matchers::ActiveModel, ebenso gut wiediese StackOverflow-Antwort zur Strukturierung von Mustertests in Modellen. Es gibt jedoch noch ein paar Dinge, bei denen ich mir nicht sicher bin, und ich frage mich, wie diese Tests verbessert werden könnten.

Ich werde die Benutzerspezifikation im Rails-Tutorial als mein Beispiel verwenden, da sie am ausführlichsten ist und viele Bereiche abdeckt, die verbessert werden könnten. Das folgende Codebeispiel wurde gegenüber dem Original geändertuser_spec.rb, und ersetzt den Code bis zumdescribe "micropost associations" Linie. Die Spezifikation testet gegen dieuser.rb Modell, und seine Fabrik ist in definiertfactories.rb.

spec / models / user_spec.rb

# == Schema Information
#
# Table name: users
#
#  id              :integer          not null, primary key
#  name            :string(255)
#  email           :string(255)
#  created_at      :datetime         not null
#  updated_at      :datetime         not null
#  password_digest :string(255)
#  remember_token  :string(255)
#  admin           :boolean          default(FALSE)
#
# Indexes
#
#  index_users_on_email           (email) UNIQUE
#  index_users_on_remember_token  (remember_token)
#

require 'spec_helper'

describe User do

  let(:user) { FactoryGirl.create(:user) }

  subject { user }

  describe "database schema" do
    it { should have_db_column(:id).of_type(:integer)
                              .with_options(null: false) }
    it { should have_db_column(:name).of_type(:string) }
    it { should have_db_column(:email).of_type(:string) }
    it { should have_db_column(:created_at).of_type(:datetime)
                              .with_options(null: false) }
    it { should have_db_column(:updated_at).of_type(:datetime)
                              .with_options(null: false) }
    it { should have_db_column(:password_digest).of_type(:string) }
    it { should have_db_column(:remember_token).of_type(:string) }
    it { should have_db_column(:admin).of_type(:boolean)
                              .with_options(default: false) }
    it { should have_db_index(:email).unique(true) }
    it { should have_db_index(:remember_token) }
  end

  describe "associations" do
    it { should have_many(:microposts).dependent(:destroy) }
    it { should have_many(:relationships).dependent(:destroy) }
    it { should have_many(:followed_users).through(:relationships) }
    it { should have_many(:reverse_relationships).class_name("Relationship")
                         .dependent(:destroy) }
    it { should have_many(:followers).through(:reverse_relationships) }
  end

  describe "model attributes" do
    it { should respond_to(:name) }
    it { should respond_to(:email) }
    it { should respond_to(:password_digest) }
    it { should respond_to(:remember_token) }
    it { should respond_to(:admin) }
    it { should respond_to(:microposts) }
    it { should respond_to(:relationships) }
    it { should respond_to(:followed_users) }
    it { should respond_to(:reverse_relationships) }
    it { should respond_to(:followers) }
  end

  describe "virtual attributes and methods from has_secure_password" do
    it { should respond_to(:password) }
    it { should respond_to(:password_confirmation) }
    it { should respond_to(:authenticate) }
  end

  describe "accessible attributes" do
    it { should_not allow_mass_assignment_of(:password_digest) }
    it { should_not allow_mass_assignment_of(:remember_token) }
    it { should_not allow_mass_assignment_of(:admin) }
  end

  describe "instance methods" do
    it { should respond_to(:feed) }
    it { should respond_to(:following?) }
    it { should respond_to(:follow!) }
    it { should respond_to(:unfollow!) }
  end

  describe "initial state" do
    it { should be_valid }
    it { should_not be_admin }
    its(:remember_token) { should_not be_blank }
    its(:email) { should_not =~ /\p{Upper}/ }
  end

  describe "validations" do
    context "for name" do
      it { should validate_presence_of(:name) }
      it { should_not allow_value(" ").for(:name) }
      it { should ensure_length_of(:name).is_at_most(50) }
    end

    context "for email" do
      it { should validate_presence_of(:email) }
      it { should_not allow_value(" ").for(:email) }
      it { should validate_uniqueness_of(:email).case_insensitive }

      context "when email format is invalid" do
        addresses = %w[user@foo,com user_at_foo.org example.user@foo.]
        addresses.each do |invalid_address|
          it { should_not allow_value(invalid_address).for(:email) }
        end
      end

      context "when email format is valid" do
        addresses = %w[[email protected] [email protected] [email protected] [email protected]]
        addresses.each do |valid_address|
          it { should allow_value(valid_address).for(:email) }
        end
      end
    end

    context "for password" do
      it { should ensure_length_of(:password).is_at_least(6) }
      it { should_not allow_value(" ").for(:password) }

      context "when password doesn't match confirmation" do
        it { should_not allow_value("mismatch").for(:password) }
      end
    end

    context "for password_confirmation" do
      it { should validate_presence_of(:password_confirmation) }
    end
  end

  # ...
end

Einige spezifische Fragen zu diesen Tests:

Lohnt es sich überhaupt, das Datenbankschema zu testen? Ein Kommentar in derDie oben erwähnte StackOverflow-Antwort "Ich teste nur verhaltensbezogene Dinge und berücksichtige das Vorhandensein einer Spalte oder eines Indexverhaltens nicht. Datenbankspalten verschwinden nur, wenn sie absichtlich entfernt werden. Sie können sich jedoch mit Codeüberprüfungen und schützen Englisch: www.mjfriendship.de/en/index.php?op...=view&id=167 Ich bin damit einverstanden, aber es gibt einen triftigen Grund, warum die Struktur des Datenbankschemas überprüft werden sollte und somit die Existenz des Datenbankschemas gerechtfertigt wirdShoulda::Matchers::ActiveRecord Modul? Vielleicht sind nur die wichtigen Indizes einen Test wert ...?Mach dasshould have_many Tests unter"associations" ersetzen ihre entsprechendenshould respond_to Tests unter"model attributes"? Ich kann nicht sagen, ob dieshould have_many test sucht nur nach dem relevantenhas_many Deklaration in einer Modelldatei oder führt tatsächlich die gleiche Funktion aus wieshould respond_to.Haben Sie weitere Kommentare / Vorschläge, um diese Tests inhaltlich und strukturell übersichtlicher / lesbarer / gründlicher zu gestalten?

Antworten auf die Frage(5)

Ihre Antwort auf die Frage