Как RSpec использовать общий модуль ActiveRecord без соответствующей таблицы базы данных?
Использование RSpec 2.6/Rails 3.1/Postgres:
Я пишу поддерживающий модуль (в моем lib/), который может включать любую AR-модель. Я бы хотел написать спецификацию для этого модуля. Он должен быть включен в модель AR:: Base, поскольку он загружает ассоциации при включении и использует некоторые методы AR, но я не хочу использовать существующую модель при написании rspec для этого модуля.
Я просто хотел бы создать произвольную AR-модель, но, очевидно, у нее не было бы таблицы, связанной в базе данных, и AR умирает. Вот kindda, что я хочу сделать:
class SomeRandomModel < ActiveRecord::Base
include MyModule
# simulate DB attributes that MyModule would be using
attr_accessor :foo, :bar, :baz
end
describe SomeRandomModel do
it '#some_method_in_my_module' do
srm = SomeRandomModel.new(:foo => 1)
srm.some_method_in_my_module.should eq(something)
end
end
Конечно, я получаю некоторую ошибку в postgres относительно отношения, которое не существует.
Спасибо за вашу помощь!
Ответы
Ответ 1
Существует альтернативный способ решения этой проблемы с помощью rpsecs shared_examples_for
, я упоминаю несколько трюков в фрагменте кода, но для получения дополнительной информации см. этот relishapp-rspec -руководство.
С этим вы можете протестировать свой модуль в любом из классов, которые его включают. Итак, вы действительно тестируете, что используете в своем приложении.
Посмотрим на пример:
# Lets assume a Movable module
module Movable
def self.movable_class?
true
end
def has_feets?
true
end
end
# Include Movable into Person and Animal
class Person < ActiveRecord::Base
include Movable
end
class Animal < ActiveRecord::Base
include Movable
end
Теперь создадим спецификацию для нашего модуля: movable_spec.rb
shared_examples_for Movable do
context 'with an instance' do
before(:each) do
# described_class points on the class, if you need an instance of it:
@obj = described_class.new
# or you can use a parameter see below Animal test
@obj = obj if obj.present?
end
it 'should have feets' do
@obj.has_feets?.should be_true
end
end
context 'class methods' do
it 'should be a movable class' do
described_class.movable_class?.should be_true
end
end
end
# Now list every model in your app to test them properly
describe Person do
it_behaves_like Movable
end
describe Animal do
it_behaves_like Movable do
let(:obj) { Animal.new({ :name => 'capybara' }) }
end
end
Ответ 2
Я столкнулся с подобной проблемой, и после долгих поисковых запросов я решил только настроить и снести таблицы в тестах RSpec. Вот фрагмент, который я использовал:
describe "stuff you are testing do" do
before :all do
m = ActiveRecord::Migration.new
m.verbose = false
m.create_table :random_class do |t|
t.string :field_1
t.integer :field_2
end
end
after :all do
m = ActiveRecord::Migration.new
m.verbose = false
m.drop_table :random_class
end
class RandomClass < ActiveRecord::Base
attr_accessible :field_1, :field_2
end
# Your regular RSpec before(:each) blocks and tests
# ...
# e.g.
it "should be able to use RandomClass" do
rc = RandomClass.create! :field_1 => "hello", :field_2 => 5
rc.field_1.should == "hello"
rc.field_2.should == 5
end
end
Я не в восторге от этого решения, но он работает. Надеюсь, что это поможет кому-то! Либо это, либо вдохновляет их опубликовать лучший способ выполнить это.
:)
Ответ 3
Вы можете переименовать self.columns
class Tableless < ActiveRecord::Base
def self.columns
@columns ||= [];
end
end
то вы можете создать новый экземпляр reguralry
let(:dummy_instance) { Tableless.new }
it { is_expected.to be_valid}
Ответ 4
goggin13, спасибо за ваш ответ. В основном это работало для меня, за исключением того, что мне пришлось изменить методы экземпляра миграции на класс. то есть:.
С
m = ActiveRecord::Migration.new
m.verbose = false
m.create_table ...
Для
m = ActiveRecord::Migration
m.verbose = false
m.create_table ...
Ответ 5
Здесь небольшая вариация ответа goggin13, которая исправляет миграцию (как заметил Zac) и исправляет имя таблицы:
describe "stuff you are testing do" do
before :all do
m = ActiveRecord::Migration
m.verbose = false
m.create_table :random_classes do |t|
t.string :field_1
t.integer :field_2
end
end
after :all do
m = ActiveRecord::Migration
m.verbose = false
m.drop_table :random_classes
end
class RandomClass < ActiveRecord::Base
attr_accessible :field_1, :field_2
end
# Your regular RSpec before(:each) blocks and tests
# ...
# e.g.
it "should be able to use RandomClass" do
rc = RandomClass.create! :field_1 => "hello", :field_2 => 5
rc.field_1.should == "hello"
rc.field_2.should == 5
end
end