在前块中创建的 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 控制器操作时被删除的主要内容,如果未能解决你的问题,请参考以下文章

RSpec:特性和请求规范有啥区别?

在另一个活动中创建的对象在主活动中不可见

图像显着减慢 Rspec 请求规范

有啥方法可以返回对函数中创建的变量的引用?

如何使用 pry 调试器检查 rspec 变量

由 awk 在 bash 中创建的索引变量