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

如何在不使用eval方法的情况下用RSpec编写参数化代码的共享示例?

嘿,我懂你不想用eval来实现RSpec共享示例参数化的心情——eval不仅代码可读性差,还暗藏安全风险,完全没必要依赖它。这里有几个更优雅、符合RSpec最佳实践的替代方案:

方案1:直接传递代码块给共享示例

RSpec的共享示例天然支持接收代码块,你可以在示例内部通过yield来执行对应的SMS发送动作,这是最直观的方式:

RSpec.shared_examples "sending an sms" do
  it "sends an sms" do
    # 执行传入的代码块,触发SMS发送动作
    yield
    expect(WebMock).to have_requested(**my_request**).with(**my_body**)
  end
end

# 使用的时候,直接在调用时传入具体的发送逻辑
it_behaves_like "sending an sms" do
  user = create(:user)
  user.send_verification_sms
end

# 针对另一个发送方法,直接换块里的内容就行
it_behaves_like "sending an sms" do
  order = create(:order)
  order.send_delivery_reminder_sms
end

方案2:传递Proc/Lambda对象

如果需要提前定义好发送逻辑,或者要传递参数给动作,用Proc或Lambda会更灵活:

RSpec.shared_examples "sending an sms" do |send_action|
  it "sends an sms" do
    # 调用传入的Proc对象执行动作
    send_action.call
    expect(WebMock).to have_requested(**my_request**).with(**my_body**)
  end
end

# 提前定义好发送逻辑的Proc
send_verification_sms = -> { create(:user).send_verification_sms }
it_behaves_like "sending an sms", send_verification_sms

# 也可以直接内联写Lambda,针对不同方法快速复用
it_behaves_like "sending an sms", -> { create(:order).send_delivery_reminder_sms }

方案3:利用let定义共享动作

如果你的测试上下文里已经有统一的对象或参数规范,可以在共享示例里依赖一个let定义的方法,然后在具体测试组里实现这个方法:

RSpec.shared_examples "sending an sms" do
  it "sends an sms" do
    # 调用提前定义好的共享动作方法
    perform_sms_action
    expect(WebMock).to have_requested(**my_request**).with(**my_body**)
  end
end

# 在第一个测试组里实现`perform_sms_action`
describe User do
  let(:perform_sms_action) { create(:user).send_verification_sms }

  it_behaves_like "sending an sms"
end

# 在第二个测试组里换个实现即可
describe Order do
  let(:perform_sms_action) { create(:order).send_delivery_reminder_sms }

  it_behaves_like "sending an sms"
end

这几个方案都完全避开了eval,代码更易读、易维护,还能享受RSpec的调试友好性——再也不用头疼eval里的代码出问题不好排查了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:51:32