【发布时间】:2011-04-11 13:40:33
【问题描述】:
Factory Girl 对于功能测试非常有用,但有一个令人讨厌的属性,使它在单元测试中使用起来稍微困难一些,我不想依赖测试数据库。我经常使用Factory.build 创建一个工厂,然后我可以使用flexmock 传递或分配给ActiveRecord.find 调用:
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
这至少可以说是不直观的,并且在我测试一些需要与 mixin 很好地配合使用的类时会导致实际问题。我希望能够做到这一点:
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 Bars 和 666 Bazes(“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 这样的东西存在吗?
【问题讨论】:
标签: ruby unit-testing factory-bot