如何使用Rspec测试非静态方法被其他方法调用
实例方法内部调用校验的RSpec实现方案
报错本质是打桩对象选错了:allow(MyService).to receive(xxx)的作用对象是MyService类本身,仅能对类方法(即def self.method_b定义的静态方法)生效,示例代码里的method_b是实例方法,自然会提示类未实现该方法。
正确实现方式
针对实例方法的打桩和调用校验,需要作用在类的实例对象上,根据场景选对应写法即可:
1. 针对具体实例打桩(推荐,无测试污染)
这是单元测试场景下的首选写法,不会影响其他测试用例的状态,示例测试代码:
RSpec.describe MyService do describe "#method_a" do it "执行时会调用method_b" do # 初始化被测对象实例 service = MyService.new # 给当前实例的method_b打桩,屏蔽原有实现、指定返回值 allow(service).to receive(:method_b).and_return(2) # 执行被测方法 service.method_a # 核心断言:验证method_b确实被调用 expect(service).to have_received(:method_b) end end end
对应被测业务代码:
class MyService def method_a a = 1 b = method_b return a + b end def method_b return 2 end end
2. 任意实例打桩(适配拿不到具体实例的场景)
如果被测逻辑会在内部自行初始化MyService实例、外部拿不到具体实例对象,可以使用any_instance语法对该类的所有实例统一打桩:
RSpec.describe MyService do describe "#method_a" do it "执行时会调用method_b" do # 给MyService所有实例的method_b打桩 allow_any_instance_of(MyService).to receive(:method_b).and_return(2) # 执行被测逻辑 MyService.new.method_a # 断言method_b被调用 expect_any_instance_of(MyService).to receive(:method_b) end end end
注意:
any_instance会对当前测试运行周期内所有MyService实例生效,存在测试状态污染风险,非必要不优先使用。
内容的提问来源于stack exchange,提问作者Aviv Day
相关产品推荐
相关产品推荐

