Rspec stub两个包含同一模块的类时抛出Transaction::Overview未实现new方法错误
问题根源
该错误与RSpec是否支持stub引入同一模块的类无关,本质是Ruby常量查找歧义:
报错中提示没有new方法的是Transaction::Overview(这是个模块,本身确实无法实例化、没有new方法),说明RSpec执行第二个stub时,错误地将你指定的Actual::Overview/Adjustment::Overview解析成了Transaction::Overview模块。
这类问题多出现于Rails自动加载(懒加载)场景:第一次访问嵌套常量时解析正确,第二次查找同名嵌套常量时,Ruby错误命中了已经加载的Transaction::Overview模块。
解决方案
方案1:提前预解析常量(最推荐)
在测试用例的起始位置,或者对应describe块的最前端,先强制Ruby完成两个目标类的常量解析,避免后续查找出现歧义:
# 提前触发常量加载,固定解析结果 Actual::Overview Adjustment::Overview
仅需两行代码即可触发Rails自动加载对应类,后续stub时常量查找就不会发生偏移。
方案2:显式获取常量
如果方案1不生效,可以通过const_get从顶层命名空间显式获取目标类,完全规避常量查找的歧义问题:
# 替换原有的stub逻辑 actual_overview_clz = Object.const_get("Actual::Overview") expect(actual_overview_clz).to receive(:new).with(activity_presenter, report_presenter).at_least(:once).and_return(actual_overview) adjustment_overview_clz = Object.const_get("Adjustment::Overview") expect(adjustment_overview_clz).to receive(:new).with(activity_presenter, report_presenter).at_least(:once).and_return(adjustment_overview)
方案3:临时关闭部分双验证
如果你确认要stub的类确实存在new方法,也可以临时关闭RSpec的部分双校验绕开检查(不推荐,会跳过方法存在性校验,可能掩盖其他问题):
without_partial_double_verification do expect(Adjustment::Overview).to receive(:new).with(activity_presenter, report_presenter).at_least(:once).and_return(adjustment_overview) end
额外排查点
可以检查测试文件、全局测试配置中是否有include Transaction之类的代码,这类写法会把Transaction下的常量引入当前命名空间,直接导致Overview的查找优先级变为Transaction::Overview优先,必然会触发解析错误。
内容的提问来源于stack exchange,提问作者Pezholio
相关产品推荐
相关产品推荐

