You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails Minitest assert_equal断言失败求助:预期与实际值不符

问题排查:相同商品添加购物车时测试失败但功能正常

场景说明

Cart与Line_item是一对多关联(Line_item属于Cart),Product与Line_item也是一对多关联(Line_item属于Product)。当向line_items_path发送POST请求时,product_id会传入line_items_controller#create方法,该方法调用cart#add_product:

  • 如果购物车中已存在相同product_id的Line_item,就将该Line_item的quantity加1
  • 如果不存在,则构建新的Line_item,后续由控制器统一保存

相关代码

line_items_controller.rb

def create
  product = Product.find(params[:product_id])
  @line_item = @cart.add_product(product.id, product.price)
  respond_to do |format|
    if @line_item.save
      format.html { redirect_to @line_item.cart }
      format.json { render :show, status: :created, location: @line_item }
    else
      format.html { render :new }
      format.json { render json: @line_item.errors, status: :unprocessable_entity }
    end
  end
end

cart.rb 的 #add_product 方法

def add_product(product_id, product_price)
  current_item = line_items.find_by(product_id: product_id)
  if current_item
    current_item.quantity += 1
  else
    current_item = line_items.build(product_id: product_id, price: product_price)
  end
  current_item
end

测试用例与报错

测试用例

test "should update quantity of existing line item when adding another of the same product" do
  cart = Cart.create
  cart.add_product(products(:product_one).id, products(:product_one).price)
  cart.add_product(products(:product_one).id, products(:product_one).price)
  assert_equal cart.line_items.size, 1 # assert_equal cart.line_items[0].quantity, 2
end

报错信息

Failure: CartsControllerTest#test_should_update_quantity_of_existing_line_item_when_adding_another_of_the_same_product [AgileWebDev/depot/test/controllers/carts_controller_test.rb:73]:
Expected: 2
Actual: 1

问题分析与解决方案

困惑点拆解

你提到的两个核心问题,我们逐一梳理解决:

  1. 断言参数顺序导致的数值矛盾
    Rails的assert_equal方法参数顺序是 assert_equal 预期值, 实际值。看你的测试代码,当前写的assert_equal cart.line_items.size, 1把「实际值」放在了第一个参数位置,「预期值」放在了第二个。如果cart.line_items.size是1,这条断言逻辑上应该通过,但报错显示Expected:2, Actual:1,说明你实际运行的断言应该是assert_equal 2, cart.line_items.size(或者你把注释里的断言写错了位置)。

    你注释里的assert_equal cart.line_items[0].quantity, 2才是符合测试意图的,但同样要修正参数顺序,正确写法是:

    assert_equal 2, cart.line_items[0].quantity
    
  2. 测试中未持久化变更导致的环境差异
    开发环境功能正常,是因为line_items_controller#create里调用了@line_item.save——不管是新建Line_item还是更新已有Line_item的quantity,这个save都会把变更写入数据库。但你的测试代码里,直接调用cart.add_product后没有保存返回的Line_item:

    • 第一次调用add_product时,build只是在内存中生成Line_item对象,不会写入数据库
    • 第二次调用add_product时,line_items.find_by(product_id: product_id)会去数据库查询,此时数据库里还没有这条记录,所以会再次build新的Line_item;即使是更新已有Line_item的quantity,current_item.quantity +=1也只是内存中的变更,不save的话数据库数值不会更新。

    修正测试代码的两种方式:

    • 方式一:在测试中手动保存Line_item,确保变更持久化
      test "should update quantity of existing line item when adding another of the same product" do
        cart = Cart.create
        # 第一次添加并保存
        line_item = cart.add_product(products(:product_one).id, products(:product_one).price)
        line_item.save
        # 第二次添加并保存
        line_item = cart.add_product(products(:product_one).id, products(:product_one).price)
        line_item.save
        # 重新加载数据,确保获取数据库最新状态
        cart.reload
        # 断言购物车中只有1条Line_item,且quantity为2
        assert_equal 1, cart.line_items.size
        assert_equal 2, cart.line_items[0].quantity
      end
      
    • 方式二:修改cart#add_product方法,更新quantity后自动保存(更推荐保持控制器统一处理保存,这里仅作备选)
      def add_product(product_id, product_price)
        current_item = line_items.find_by(product_id: product_id)
        if current_item
          current_item.quantity += 1
          current_item.save # 新增保存逻辑
        else
          current_item = line_items.build(product_id: product_id, price: product_price)
        end
        current_item
      end
      

总结

核心问题是测试代码的断言参数顺序错误,加上未持久化内存中的变更,导致测试与开发环境行为不一致。调整断言顺序并确保Line_item的变更保存到数据库后,测试就能正常通过了。

内容的提问来源于stack exchange,提问作者jbk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:14:13