在前块中创建的 Rspec 变量在功能规范到达 POSTed 控制器操作时被删除
Posted
技术标签:
【中文标题】在前块中创建的 Rspec 变量在功能规范到达 POSTed 控制器操作时被删除【英文标题】:Rspec variable created in before block is deleted by the time feature spec reaches POSTed controller action 【发布时间】:2020-06-26 13:45:44 【问题描述】:我有一个truncation
数据库清理策略,所以不知道为什么会发生这种情况。基本上只是做一个单一的功能规范来测试订单是否被正确创建。
require 'rails_helper'
describe "create successfully", type: :feature, js: true do
before do
@site = create(:site)
visit "/orders"
.... # various actions to build an order using the page's form
puts ">>>>>"
puts "site in before action: #Site.all.size"
find("#checkoutModal #submit").click()
sleep(1)
end
it "should create" do
expect(Order.all.size).to equal(1)
end
end
# controller action that #submit POSTs to
def create
puts ">>>>>"
puts "site in controller create: #Site.all.size"
@order = Order.new(order_params)
@order.save if @order.valid?
end
# puts output:
>>>>>
site in before action: 1
>>>>>
site in controller create: 0
规范失败,因为@order 创建依赖于@site
。关于@site 为何被破坏的任何想法?我再次正确设置了截断:
# rails_helper.rb
Rspec.configure do |config|
config.use_transactional_fixtures = false
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, js: true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each, truncate: true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
【问题讨论】:
【参考方案1】:一个更好的测试方法是使用change匹配器:
Rspec.feature "Creating orders", js: true do
let!(:site ) create(:site)
def fill_in_and_submit_form
visit "/orders"
# ...
fill_in "something", with: attributes[:something]
find("#checkoutModal #submit").click()
end
context "with valid attributes" do
let(:attributes) attributes_for(:order)
it "creates an order" do
expect do
fill_in_and_submit_form
end.to change(Order, :count).by(1)
end
end
context "with invalid attributes" do
let(:attributes) do
# should be a hash with invalid attributes
end
it "does not create an order" do
expect do
fill_in_and_submit_form
end.to_not change(Order, :count)
end
end
end
这会在评估块之前和之后创建一个计数查询。 .size
应该记住的一件事是,如果集合已经加载,它将返回集合的长度。这不是一件好事,因为您需要一个 db 计数。
将您的***功能描述命名为“创建成功”不是一个好主意。它没有描述您正在测试什么,它需要您创建两个文件来测试成功和失败。
那个控制器也是完全错误的。
def create
@order = Order.new(order_params)
if @order.save
redirect_to @order
else
render :new
end
end
@order.save if @order.valid?
很傻。 .save
将验证记录并在其有效时将其保留。您真的只是想检查 save 的返回值,以查看记录是否已实际保存到数据库中。如果 orders 是一个嵌套记录,它实际上也应该是这样的:
def create
@site = Site.find(params[:site_id]) # you're not passing it through a hidden input are you?
@order = @site.orders.new(order_params)
if @order.save
redirect_to @order
else
render :new
end
end
【讨论】:
感谢您的帮助!在这种情况下,我只是好奇地想知道,为什么@site
会被破坏???是的,控制器很愚蠢,在实际代码中,.valid?
和 .save
之间发生了更多事情,这对于这个问题来说是不必要的
我实际上不是 100% 确定,因为它可能是任何数量的东西。 DB 清理器设置看起来不错,但在现代版本的 Rails 中并不真正需要它。
感谢您的快速响应!如果我可以再问一个问题,不想拖拖拉拉,这行问题的原因是因为我在order
中有一个回调,它查看它的父级site
,(例如,before_validation :add_call_number_to_order
其中该方法确实self.call_number = self.site.start_number
)。当然,由于没有站点,我得到一个 no method 错误,因为order.site = nil
。这就是我重新设置手动数据库清理器的原因,因为我认为这是问题所在。但如果不是……这些类型的规范通常如何通过?
我真的希望你问一个单独的问题。以上是关于在前块中创建的 Rspec 变量在功能规范到达 POSTed 控制器操作时被删除的主要内容,如果未能解决你的问题,请参考以下文章