Rails模型merge_items方法在RSpec测试中失效问题求助
问题:ShoppingCart的merge_items方法在RSpec测试中未生效
我在ShoppingCart模型中实现了merge_items方法,用于合并拥有相同variant_id的ShoppingCartItem并累加它们的quantity。手动测试时该方法运行正常,但在RSpec测试中似乎被忽略——测试用例中添加两个同variant_id的项后,期望items数量为1,实际得到2。
模型代码
class ShoppingCart < ApplicationRecord belongs_to :company belongs_to :user has_many :items, class_name: "ShoppingCartItem", dependent: :destroy accepts_nested_attributes_for :items, reject_if: proc { |attributes| attributes['quantity'].blank? } before_validation :remove_invalid_items before_validation :merge_items def merge_items self.items = items.group_by { |i| i[:variant_id] }.map do |variant_id, is| quantity_sum = is.sum { |i| i[:quantity] } ShoppingCartItem.new(variant_id: variant_id, quantity: quantity_sum) end end end
测试代码
require 'rails_helper' RSpec.describe ShoppingCart, type: :model do describe "associations" do it { is_expected.to belong_to(:company) } it { is_expected.to belong_to(:user) } it { is_expected.to have_many(:items) } end describe "merge_items" do let(:shopping_cart) { create(:shopping_cart) } it "merge items if same variant_id" do existing_item = create(:shopping_cart_item, shopping_cart: shopping_cart, variant_id: "same variant_id", quantity: 1) item = create(:shopping_cart_item, shopping_cart: shopping_cart, variant_id: "same variant_id", quantity: 1) expect(shopping_cart.reload.items.count).to eq(1) end it "not merge items if variant_id different" do existing_item = create(:shopping_cart_item, shopping_cart: shopping_cart, variant_id: "variant_id", quantity: 1) item = create(:shopping_cart_item, shopping_cart: shopping_cart, variant_id: "different variant_id", quantity: 1) expect(shopping_cart.reload.items.count).to eq(2) end end end
测试失败信息
Failure/Error: expect(shopping_cart.reload.items.count).to eq(1) expected: 1 got: 2
原因分析
测试中直接用create(:shopping_cart_item)创建关联项的方式,是直接向数据库插入记录,不会触发ShoppingCart模型的before_validation回调——回调只有在ShoppingCart实例本身执行验证操作(比如save、update、valid?)时才会触发。当前测试流程中没有触发购物车的验证,所以merge_items方法根本没被调用。
解决方案
方案1:触发购物车的保存/验证操作
在创建完子项后,调用购物车的save或valid?方法触发回调,再重新加载验证结果:
it "merge items if same variant_id" do create(:shopping_cart_item, shopping_cart: shopping_cart, variant_id: "same variant_id", quantity: 1) create(:shopping_cart_item, shopping_cart: shopping_cart, variant_id: "same variant_id", quantity: 1) shopping_cart.save # 触发before_validation回调 expect(shopping_cart.reload.items.count).to eq(1) end
方案2:通过购物车关联添加项(更贴合实际业务流程)
直接通过购物车的items关联构建子项,再保存购物车,确保回调被触发:
it "merge items if same variant_id" do shopping_cart.items.build(variant_id: "same variant_id", quantity: 1) shopping_cart.items.build(variant_id: "same variant_id", quantity: 1) shopping_cart.save expect(shopping_cart.reload.items.count).to eq(1) end
方案3:使用嵌套属性更新(模拟前端传参场景)
通过嵌套属性更新购物车,更贴近实际业务中添加购物车项的流程:
it "merge items if same variant_id" do shopping_cart.update(items_attributes: [ { variant_id: "same variant_id", quantity: 1 }, { variant_id: "same variant_id", quantity: 1 } ]) expect(shopping_cart.reload.items.count).to eq(1) end
内容的提问来源于stack exchange,提问作者Mohamed Bengrich
相关产品推荐
相关产品推荐

