Popular Posts

четверг, 12 января 2012 г.

Печём для моделей. Тестируем модели в rails

Привет.
Сегодня я покажу, как протестировать модели в rails. Для этого мы будем использовать RSpec - специальная утилита для Ruby. Сделана для BDD.
Сперва устанавливаем необходимые gem'ы.
gem install rspec
gem install factory_girl_rails
gem install rspec-rails
gem install shoulda-matchers
Первых два gem'а это непосредственно rspec и rspec для rails. Третий gem - это фабрика, которуб будет использовать вместо фикстур. Последний для тестирования ассоциаций.


и так у меня есть две модели: Post и Comment.
Таблицы для них элементарные:
- posts
   - title
   - content
 - comments
   - name
   - comment
   - post_id


Пост может иметь много комментариев - зависимость has_many.
Также я проверяю, чтобы все поля были заполнены - валидатор presence, а также для названия поста проверяю длину (от 3 символов).


Таким образом классы:
#/models/post.rb
Class Post < ActiveRecord::Base
   validates :title, :presence => true
   validates :content, :presence => true
   validates :title, :length => { :minimum => 3 }
#асосиации
   has_many :comments
end

#/models/comment.rb
Class Comment < ActiveRecord::Base
   validates :name, :presence => true
   validates :comment, :presence => true
#связываем 
   belongs_to :post
end

Всё, модели готовы.


Теперь напишем элементарные тесты, но для начала нужно включить установленные gem'ы в Gemfile:


#Gemfile
group :test do
  gem "rspec" 
  gem "rspec-rails"
  gem "factory_girl_rails"
  gem "shoulda-matchers"
end

Сейчас генерируем спеки:
rails g rspec:install

Эта команда генерирует директории для контроллеров, моделей, хелперов и так далее.


Отлично. Теперь самое интересное пишем тесты спеки.


#/spec/models/post_spec.rb
require 'spec_helper'

describe Post do
  #сначала проверяем валидаторы
  context "validates" do
     before(:each) do
        @post = Factory.create(:post)
     end
     
     #должна быть валидная, если валидные атрибуты (title, content)
     it "is valid with valid attributes" do
       @post.should be_valid
     end
     
     #не валидная без title   
     it "is not valid without a title" do
        @post.title = nil
        @post.errors_on(:title).should include("can't be blank")  
        @post.should be_valid
     end
     
     #не валидная без content'а
     it "is not valid without a content" do
               @post.content = nil
               @post.errors_on(:content).should include("can't be blank")
               @post.should_not be_valid
          end
     
      #не валидная, если длина названия, меньше чем 3 символа
           it "is not valid if length of title less then 3 characters" do
               @post.title = "12"
               @post.should_not be_valid
           end
      
      #валидная с длиной больше, чем 3 символа
           it "is valid if length of title greater then 3 characters" do
               @post.title = "123"
               @post.should be_valid
           end
   end
end
Что я использовал здесь.
Сперва я подписался на Post, (describe Post)
Затем я разбил всё на контексты (context), первый это валидаторы.
Затем методами it, я проверял утверждения, например: Длина названия должна быть больше 3 символов - это просто утверждение, проверяется в методе it. Но перед вызовами каждого теста, я устанавливал @post - это происходит в методе before(:each). Проверка происходит методами RSpec, should, should_not (должен и не должен). Например:


      #валидная с длиной больше, чем 3 символа
           it "is valid if length of title greater then 3 characters" do
               @post.title = "123"
               @post.should be_valid
           end


будет звучать так: Если длина названия содержит более чем 3 символа, то пост валиден.


Тоже самое пишем и для модели Comment


#/spec/models/comment_spec.rb
describe Comment do
   context "validates" do 
       before(:each) do
             @comment = Factory.create(:comment)
        end

   
        it "is valid with valid attributes" do
              @comment.should be_valid
          end

          it "is invalid without name" do
             @comment.name = nil
             @comment.should_not be_valid
          end

          it "is invalid without comment" do
             @comment.comment = nil
             @comment.should_not be_valid
          end
     end
 end
end


Как видем тоже самое, проверка имени и комментария.
Что дальше, теперь напишем тесты для ассоциаций, всё это можно было бы сделать и без shoulda, но с ним более удобно. Но не удобно (для меня) тестировать валидаторы, поэтому я применяю этот gem для тестирования ассоциаций.
Добавляем контексты


#/spec/models/post_spec.rb

context "associations" do
    it "should have many comments depending" do
               should have_many(:comments) #пост имеет много комментариев
         end
end
#/spec/models/comment_spec.rb
context "associations" do
       it "should belongs_to post" do
          should belong_to(:post) #комментарии должны быть связаны с постом
       end
end
Теперь, что с Factory Girl (хорошее название)
фактори делает не нужными фикстуры, кто с ними работал, тот знает, что написание фикстур это утомительно, очень утомительно.


#/spec/factories/factoryes.rb

FactoryGirl.define do
   factory :post do
       title "Title"
       content "Content"
   end
end

FactoryGirl.define do
   factory :comment do
        name "Foo"
        comment "Bar"
        post
   end
end
Когда мы делаем Factory.create(:post), то получаем модель с  задаными атрибутами. Всё просто, не фикстуры.


Теперь запускаем тесты, так как я написал спеки только для моделей, то и запускать буду для моделей:
rake spec:models
===>
/home/xxx/.rvm/rubies/ruby-1.9.3-p0/bin/ruby -S rspec ./spec/models/post_spec.rb ./spec/models/comment_spec.rb
..........


Finished in 0.13836 seconds
10 examples, 0 failures


 
Ссыли:


https://github.com/thoughtbot/shoulda-matchers
https://github.com/rspec/rspec-rails
https://github.com/thoughtbot/factory_girl

Комментариев нет:

Отправить комментарий