Undr

На память

Записи с меткой ‘module’

Тестирование модулей с помощью RSpec

without comments

1 Star2 Stars3 Stars4 Stars5 Stars (1 голосов, средний: 5.00 из 5)
Loading ... Loading ...

К примеру, у нас есть такой модуль, который мы добавляем в классы Airport, City:

  module Nameable
    extend ActiveSupport::Concern
   
    module InstanceMethods
      def name locale=:en
        locale = :en if !name_ru || name_ru.empty?
        send(name_method(locale))
      end
   
      def localized_name
        name(I18n.locale || :en)
      end

      private
      def name_method locale=:en
        "name_#{locale}".to_sym
      end
    end
   
    included do
      field :name_en, :type => String
      field :name_ru, :type => String
      validates_presence_of :name_en
    end
  end
  class Airport
    include Mongoid::Document
    include Nameable
  end
  class City
    include Mongoid::Document
    include Nameable
  end

Чтобы протестировать модуль, для него нужно создать shared_examples_for блок:

  shared_examples_for :Nameable do  
    it{should have_fields(:name_en).of_type(String)}
    it{should have_fields(:name_ru).of_type(String)}
    it{should validate_presence_of(:name_en)}

    describe '#name' do
      specify{nameable.name(:en).should == 'Name'}
      specify{nameable.name(:ru).should == 'Имя'}
 
      context 'if russian name is null' do
        before do
          nameable.name_ru = nil
        end
   
        specify{nameable.name(:en).should == 'Name'}
        specify{nameable.name(:ru).should == 'Name'}
      end
    end
   
    # И так далее...
  end

В блоке используется одна переменная nameable, которая будет определяться в спеке того класса, к которому мы подключим модуль. То есть в spec/models/airport_spec.rb пишем примерно так:

require 'spec_helper'
require 'models/nameable_spec'

describe Airport do
  it{should be_mongoid_document}
 
  before do
    Airport.delete_all
  end
 
  context do
    let(:nameable){Factory.create(:airport,
      :name_en => 'Name',
      :name_ru => 'Имя'
    )}
    it_behaves_like :Nameable
  end

Вобщем то, переменных может быть сколько угодно, это зависит от тестируемого модуля. Теперь добавляем примерно тоже самое в spec/models/city_spec.rb:

require 'spec_helper'
require 'models/nameable_spec'

describe City do
  it{should be_mongoid_document}
 
  before do
    City.delete_all
  end
 
  context do
    let(:nameable){Factory.create(:city,
      :name_en => 'Name',
      :name_ru => 'Имя'
    )}
    it_behaves_like :Nameable
  end

Запускаем тест:

undr$ bundle exec rspec spec/models/airport_spec.rb

Работает. Запускаем несколько тестов:

undr$ bundle exec rake spec:models

Тесты вызывают ошибку:

/Users/undr/.rvm/gems/ruby-1.9.2-p180/gems/rspec-core-2.6.4/lib/rspec/core/shared_example_group.rb:59:in `ensure_shared_example_group_name_not_taken': Shared example group 'Nameable' already exists (ArgumentError)
    from /Users/undr/.rvm/gems/ruby-1.9.2-p180/gems/rspec-core-2.6.4/lib/rspec/core/shared_example_group.rb:8:in `shared_context'
    from /Users/undr/projects/ruby/*******/spec/models/nameable_spec.rb:1:in `<top (required)>'
    from /Users/undr/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.1.0/lib/active_support/dependencies.rb:234:in `load'
    from /Users/undr/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.1.0/lib/active_support/dependencies.rb:234:in `block in load'
...

Чтобы избежать этого надо предотвратить повторное определение блока shared_examples_for. Просто этот перед определением блока делайте проверку на его наличие:

unless RSpec.world.shared_example_groups.has_key?(:Nameable)
  shared_examples_for :Nameable do  
   
    ...
   
  end
end

Таким образом у меня получилось удобно, без лишнего кода, тестировать модули подмешанные к классам.

Написал undr ()

21 октября 2011 в 09:30