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

如何在Rails 5与Minitest中创建Stub方法?订单创建打桩失败求助

如何为StraightServerKit的orders.create方法打桩(Minitest)

看起来你遇到的核心问题是:被测代码里的order方法内部新建了一个完全独立的StraightServerKit::Client实例,而你测试中手动创建的client和这个内部实例毫无关系,所以之前的stub都没命中真实被调用的对象。下面给你两种可行的解决方案,以及分析你之前的错误原因。

正确方案1:使用Mocha(推荐)

Mocha的链式stub可以很方便地处理这种嵌套方法调用的场景,我们需要逐层mock:先让Client实例的orders方法返回一个mock对象,再让这个mock对象的create方法返回预设值。

require 'mocha/minitest'

test "should create order without real API request" do
  # 1. 创建一个mock的orders对象,指定它的create方法行为
  mock_orders = mock()
  # 可以用expects确保create被调用,或者用stubs只返回值
  mock_orders.expects(:create)
             .with(instance_of(StraightServerKit::Order)) # 验证传入的参数类型
             .returns("mock_order_response") # 预设返回值

  # 2. 让所有Client实例调用orders方法时返回这个mock_orders
  StraightServerKit::Client.any_instance.stubs(:orders).returns(mock_orders)

  # 3. 执行被测请求
  post post_order_path, params: { order: { amount: 10 } }
  assert_response :success
end

正确方案2:使用Minitest原生Stub(无需额外gem)

如果你不想用Mocha,也可以用Minitest自带的stub_any_instance来实现:

require 'minitest/stub_any_instance'

test "should create order with Minitest native stub" do
  # 1. 创建一个模拟的orders对象,实现create方法
  mock_orders = Object.new
  def mock_orders.create(order_obj)
    # 这里可以根据需要返回任意预设数据
    { id: "mock_123", amount: order_obj.amount }
  end

  # 2. 拦截Client所有实例的orders方法,返回我们的mock_orders
  StraightServerKit::Client.stub_any_instance(:orders, mock_orders) do
    # 3. 执行请求
    post post_order_path, params: { order: { amount: 10 } }
    assert_response :success
  end
end

为什么你之前的方法失败?

我们来逐个分析你踩的坑:

  1. 第一个测试(手动创建client后stub):
    你测试里创建的client是独立的对象,而被测代码的order方法里会重新new一个全新的Client实例,这两个实例没有任何关联,所以你对这个手动client的stub根本不会被调用到。

  2. 方法1(stub_any_instance用错):
    stub_any_instance是类方法,你应该在StraightServerKit::Client类上调用,而不是在实例上。而且你要stub的是orders方法(因为代码里是client.orders.create),不是order或者new,所以调用方式完全错误。

  3. 方法2(Mocha stub new实例方法):
    new是类方法,不是实例方法,所以StraightServerKit::Client.any_instance.stubs(:new)完全无效。如果要stub Client的创建,应该用StraightServerKit::Client.stubs(:new).returns(mock_client),然后再给mock_client的orders方法打桩。

  4. 方法3(stub_any_instance针对new):
    new是类方法,stub_any_instance是用来stub实例方法的,所以这里会报错“undefined method `new' for class”,逻辑完全不对。

关键总结

  • 打桩前一定要理清被测代码的对象创建流程,确保你stub的是实际被调用的那个对象的方法。
  • 对于嵌套方法调用(a.b.c),需要逐层打桩:先让a.b返回一个mock对象,再让这个mock对象的c方法返回预设值。
  • 当被测代码内部新建实例时,用any_instance(Mocha)或stub_any_instance(Minitest)来覆盖所有实例的方法,或者stub类的new方法返回预设的mock实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:47:19