如何在RSpec mock中返回undefined以测试使用defined?的Ruby代码
核心问题说明
你当前的业务代码存在逻辑误区:Ruby 的局部变量定义是在语法解析阶段完成的,只要你在当前作用域写了 result = MyService.something(object) 这行代码,不管后续赋值是否成功、方法返回什么值,defined? result 都会永远返回真值,你的 else 分支永远不会被执行,现有逻辑本身无法达到预期效果。
实现方案
方案1:修改业务判断逻辑(推荐)
把判断规则从「判断变量是否定义」调整为「判断返回值是否符合预期」,可以约定一个专属哨兵值代表无有效返回:
调整后业务代码
has_result = false attempts = 0 # 自定义哨兵值,唯一标识无有效返回的场景 NO_VALID_RESULT = Object.new until has_result do result = MyService.something(object) if result != NO_VALID_RESULT has_result = true else attempts += 1 end end
对应RSpec测试代码
my_service = class_double('MyService').as_stubbed_const(transfer_nested_constants: true) # 直接返回约定的哨兵值即可触发重试逻辑 allow(my_service).to receive(:something).and_return(NO_VALID_RESULT) expect(something_else).to receive(:fail!)
方案2:兼容现有逻辑的特殊实现
如果因特殊约束不能修改业务代码的判断规则,只能通过让方法调用跳出当前作用域的方式实现需求,比如把方法调用失败的场景改为抛出异常,调整代码如下:
调整后业务代码
has_result = false attempts = 0 until has_result do begin result = MyService.something(object) has_result = true rescue attempts += 1 end end
对应RSpec测试代码
my_service = class_double('MyService').as_stubbed_const(transfer_nested_constants: true) # 让模拟方法抛出异常即可跳过赋值逻辑 allow(my_service).to receive(:something).and_raise("调用无返回") expect(something_else).to receive(:fail!)
内容的提问来源于stack exchange,提问作者howells699
相关产品推荐
相关产品推荐

