我正在构建一个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
,然后{ {1}},在第二个测试中,第二个示例的ID应该为create
,而不是1
)。我不确定各种策略的确切含义-我发现this question似乎用SQL语法来解释它们,但是我对那不是很熟悉,所以我的理解是还是很模糊。我相信数据库是
使用PostgreSQL进行管理,但是我很少需要通过PostgreSQL直接与它进行交互,所以我并不是特别有经验。
因此,在每个示例之间,我的数据库都是完全删除并从头开始构建的-如果我想要一个干净的数据库,那么这是理想的选择,但是如果我想简单地加载固定装置,则可能需要一段时间才能创建所有模型。感觉我应该能够拥有固定装置的“缓存”版本,对于适合的示例,我可以加载该版本。但是我什至不知道如何做到这一点,即使有可能。有办法吗?
编辑:在评论中进行了讨论之后,我怀疑我可能想删除Database Cleaner并改用默认的Rails固定装置。我已经尝试过了,唯一遇到的问题就是上述2
策略所遇到的问题。也就是说:当回退测试创建的记录时,transaction
不会回退,这是很尴尬的行为。如果出于运行测试的目的创建了id
,则将其简称为user
是很方便的,如果不重置User.find(1)
则是不可能的。
这可能是某种危险信号,我不应该这样做(我愿意做其他事情)。我也意识到我可以说id
以获得相同的行为,这可能会更好。我不确定什么合适。
答案 0 :(得分:1)
DatabaseCleaner不适用于固定装置。它打算与工厂一起使用。 ActiveRecord::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
这是一个可以生成psuedorandom值的好的工厂的示例:
require 'ffaker'
FactoryBot.define do
factory :user do
first_name { FFaker::Name.first_name }
last_name { FFaker::Name.last_name }
end
end