我正在构建一个Rails应用程序(我是新手,所以请原谅我,如果一些措辞是笨拙的)。我正在尝试编写测试(使用RSpec)绘制和使用数据库中的数据,我在编写测试时遇到了麻烦。
某些测试(例如注册用户或创建内容)似乎最适合拥有一个新的数据库,而有些则需要数据库填充的数据库。
目前我正在使用数据库清理器gem,具有以下配置:
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
DatabaseCleaner.strategy = :truncation end
# start the transaction strategy as examples are run
config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end
我在两种策略中使用truncation
的原因是我更喜欢在示例之间完全刷新id
值(因此,如果我在一次测试中使用create
,然后在第二次测试中使用create
,则第二个示例应该具有id 1
而不是2
)。我不确定各种策略究竟是什么意思 - 我发现this question似乎用SQL语法来解释它们,但我对此并不十分熟悉,所以我的理解仍然很模糊。我相信数据库是用PostgreSQL管理的,但我很少通过它直接与它进行交互,所以我不是特别有经验。
因此,我的数据库完全被删除并在每个示例之间从头开始构建 - 如果我想要一个干净的数据库,那么这是理想的,但如果我想简单地加载灯具,那么创建所有模型可能需要一段时间。感觉我应该能够拥有一个“缓存”版本的灯具,我可以加载它适合的那些例子。但我不知道怎么做,如果有可能的话。有办法吗?
编辑:在评论中讨论之后,我怀疑我可能想要删除数据库清理程序并使用默认的Rails工具。我试过这个,我遇到的唯一问题就像我上面描述的transaction
策略一样。也就是说:当回滚测试创建的记录时,id
不会回滚,这是一种尴尬的行为。如果我为了运行测试而创建一个user
,那么就像User.find(1)
一样引用它是很方便的,如果id
没有重置则这是不可能的。
这可能是某种红旗,我不应该这样做(我愿意做其他事情)。我也意识到我可以说User.first
得到相同的行为,这可能会更好。我不确定什么是合适的。
DatabaseCleaner不适用于灯具。它旨在与工厂一起使用。 ActiveRecord::Fixtures
有自己的回滚机制。
有一个非常大的概念差异。
Fixtures就像这组巨大的静态虚拟数据,每个示例都被抛入数据库,然后通过事务重置。固定装置的最大特点是,您拥有的固定装置越多,应用程序的初始状态就越复杂,并且它会促使测试和固定装置之间的紧密耦合。
这是一个示例,显示了“Marko Anastasov”值如何从代码之外的某处神奇地出现:
RSpec.describe User do
fixtures :all
describe "#full_name" do
it "is composed of first and last name" do
user = users(:marko)
expect(user.full_name).to eql "Marko Anastasov"
end
end
end
尽管最近由于感觉简单(以及Minitest),灯具已经复苏。
工厂是生产独特记录的对象工厂。您可以使用空白状态启动每个示例,然后使用工厂以准确的状态填充数据库以复制您正在测试的方案,而不是让一堆垃圾浮动。如果做得好,这可以最大限度地减少测试订购问题,拍打测试和更换灯具破坏测试。
RSpec.describe User do
describe "#full_name" do
it "is composed of first and last name" do
user = FactoryBot.create(:user)
expect(user.full_name).to eql "#{user.first_name} #{user.last_name}"
end
end
end
这是一个生成伪随机值的好工厂的示例:
require 'ffaker'
FactoryBot.define do
factory :user do
first_name { FFaker::Name.first_name }
last_name { FFaker::Name.last_name }
end
end