如何在不使用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
相关产品推荐
相关产品推荐

