ruby-on-rails 在RSpec中运行特性测试时,有没有办法强制不销毁记录?(Rails 6)

i7uaboj4  于 2023-02-01  发布在  Ruby
关注(0)|答案(1)|浏览(117)

对于上下文,我有一个名为delete_cars的控制器方法。在该方法中,我在CarActiveRecord::Collection上调用destroy_all。在destroy_all下面,我调用另一个方法get_car_nums_not_deleted_from_portal,如下所示:

def get_car_nums_not_deleted_from_portal(cars_to_be_deleted)
  reloaded_cars = cars_to_be_deleted.reload
  car_nums = reloaded_cars.car_numbers

  if reloaded_cars.any?
    puts "Something went wrong. The following cars were not deleted from the portal: #{car_nums.join(', ')}"
  end

  car_nums
end

这里,我检查在destroy_all事务期间是否有未删除的汽车,如果有,我就添加一条puts消息,还返回ActiveRecord::Collection是否有记录,以便后面的代码可以处理它。
我的一个特性测试的目标是模拟用户试图删除三辆选定的汽车,但其中一辆未能删除。当这种情况发生时,我会在页面上显示一个特定的通知,说明:

'Some selected cars have been successfully deleted from the portal, however, some have not. The '\
"following cars have not been deleted from the portal:\n\n#{some_car_numbers_go_here}"

当我的代码执行destroy_all时,如何强制一条记录失败,而不向我的Car模型添加额外的代码(以before_destroy或类似的形式)?我尝试过使用spy,但问题是,当它被创建时,它在DB中不是一条真实的的记录,因此我的查询:

cars_to_be_deleted = Car.where(id: params[:car_ids].split(',').collect { |id| id.to_i })

不包括在内。
要了解更多背景信息,请参阅以下测试代码:

context 'when at least one car is not deleted, but the rest are' do
  it "should display a message stating 'Some selected cars have been successfully...' and list out the cars that were not deleted" do
    expect(Car.count).to eq(100)
    visit bulk_edit_cars_path
    select(@location.name.upcase, from: 'Location')
    select(@track.name.upcase, from: 'Track')
    click_button("Search".upcase)

    find_field("cars_to_edit[#{Car.first.id}]").click
    find_field("cars_to_edit[#{Car.second.id}]").click
    find_field("cars_to_edit[#{Car.third.id}]").click
    click_button('Delete cars')

    cars_to_be_deleted = Car.where(id: Car.first(3).map(&:id)).ids
    click_button('Yes')

    expect(page).to have_text(
                      'Some selected cars have been successfully deleted from the portal, however, some have not. The '\
                      "following cars have not been deleted from the portal:\n\n#{@first_three_cars_car_numbers[0]}".upcase
                    )
    expect(Car.count).to eq(98)
    expect(Car.where(id: cars_to_be_deleted).length).to eq(1)
  end
end

任何帮助这将是非常感谢!它变得相当令人沮丧的哈哈。

gwbalxhn

gwbalxhn1#

如果有特定原因导致删除失败,则可以模拟这种情况。
假设您有一个RaceResult记录,它必须始终引用有效的Car,并且您有一个强制执行此操作的DB约束(在Postgres中:您可以编写一个测试,为您的一些Car记录创建RaceResult记录:

it 'Cars prevented from deletion are reported` do
  ...
  do_not_delete_cars = Car.where(id: Car.first(3).map(&:id)).ids
  do_not_delete_cars.each { |car| RaceResult.create(car: car, ...) }

  click_button('Yes')

  expect(page).to have_text(...
end

另一种选择是使用控制器如何与模型交互的一些知识:

allow(Car).to receive(:destroy_list_of_cars).with(1,2,3).and_return(false) # or whatever your method would return

这实际上不会运行destroy_list_of_cars方法,因此所有记录仍然在DB中,然后您可以期待针对每个所选记录的错误消息。
或者,由于destroy_all调用每条记录的destroy方法,因此可以模拟该方法:

allow_any_instance_of('Car').to receive(:destroy).and_return(false) # simulates a callback halting things

然而,allow_any_instance_of使测试变脆。
最后,您可以考虑在问题出现之前不要预测它们(也许你甚至不需要批量删除页面来提供帮助?)如果你的用户看到一个更常见的错误,有没有一个页面可以过滤,以验证自己可能仍然存在什么?(这里有很多因素需要考虑,这取决于该特征对业务的重要性以及如果数据不一致会发生什么样的错误)。

相关问题