Factory Girl невероятно полезен для функционального тестирования, но имеет одно раздражающее свойство, которое немного усложняет его использование в модульных тестах, где я не хочу полагаться на тестовую базу данных.Я часто использую Factory.build
для создания фабрики, которую затем могу передать или назначить на ActiveRecord.find
вызов, используя flexmock :
require 'test_helper'
require 'flexmock'
class SomeMixinTest < ActiveSupport::TestCase
include FlexMock::TestCase
def setup
@foo = Factory.build(:foo, :id => 123,
:bar => Factory.build(:bar, :id => 456,
:baz => Factory.build(:baz, :id => 789)
)
)
flexmock Foo, :find => @foo
end
def test_find_by_reverse_id
assert_equal @foo, Foo.find_by_reverse_id(321)
end
end
Этот шаблон очень хорош, так какне заботится о наличии базы данных и работает намного быстрее, чем если бы объекты должны были сохраняться.Однако немного раздражает необходимость создавать связанные объекты вручную.Если вы этого не сделаете, связанные объекты на самом деле создаются в базе данных с помощью вызова build
, как если бы вы использовали create
.
assert_equal [], Foo.all
foo = Factory.build :foo # build my associations too, please
assert_equal [], Foo.all # look Ma, no mocks!
assert_equal [], Bar.all # <=== ASSERTION FAILED
assert_equal [], Baz.all
Это не- Интуитивно понятный, если не сказать больше, и вызывает реальную проблему, когда я тестирую несколько классов, которые должны хорошо играть с миксином.Я хочу быть в состоянии сделать это:
KLASSES_UNDER_TEST = [Foo, Bar, Baz]
def test_find_by_reverse_id
KLASSES_UNDER_TEST.each do |klass|
objects = (123..456).map do |id|
Factory.build klass.to_s.downcase.to_sym, :id => id
end
flexmock klass, :all => objects
objects.each do |object|
assert_equal object, klass.find_by_reverse_id(object.id.to_s.reverse), "#{klass} #{object.id}"
end
end
Но у этого есть неприятный побочный эффект создания 333 Bar
с и 666 Baz
эс ("Баз" действительно звучит как прозвище демонатак что, возможно, это уместно) в базе данных, что делает этот тест медленнее, чем патока, текущая в гору зимой.
Я хотел бы создать вспомогательный метод, подобный этому:
def setup_mocks(klass)
klass_sym = klass.to_s.downcase.to_sym
objects = (123..456).map{|id|
associated_objects = Hash[
Factory.associations(klass_sym).map do |association|
[ association, setup_mocks(association, 1) ]
end
]
Factory.build klass_sym, associated_objects
end
flexmock klass, :all => objects
objects
end
Итак, существует что-нибудь вроде Factory.associations
?