在Rails RSpec中如何正确对比类定义以校验配置是否符合预期
根因分析
你遇到的对比失败问题是Rails类自动重载机制导致的:Rails在开发、测试环境默认开启类自动重载,检测到代码文件变更后会重新加载常量定义。初始化器在应用启动阶段就完成了执行,其中存储的My::App::Klass是首次加载生成的旧类对象,测试运行时如果触发了重载,当前上下文的My::App::Klass就是新生成的类对象,两者object_id不同,所以基于对象身份的be匹配器、基于默认==实现的eq匹配器都会判定为不相等。
替代方案
- 对比类全限定名(最推荐)
每个Ruby类/模块的name方法都会返回全局唯一的全路径字符串,不受类重载影响,比对比inspect结果更稳定(inspect会携带属性、父类等可变信息):
expect(config[:my_app_class].name).to eq(My::App::Klass.name)
- 校验继承关系(兼容子类场景)
如果你的gem允许配置传入My::App::Klass的子类,可以用类的<=运算符判断继承关系:
# 验证配置的类是My::App::Klass本身或它的子类 expect(config[:my_app_class]).to be <= My::App::Klass
- 关闭测试环境类重载(适配原有测试逻辑)
如果不想调整测试代码,可以在config/environments/test.rb中设置config.cache_classes = true,关闭类自动重载后,初始化器存储的类对象和测试运行时的类对象会是同一个实例,你原本写的be/eq匹配器都可以正常生效。该方案的缺点是修改代码后需要重启测试进程才能加载变更,更适合CI环境使用。
内容的提问来源于stack exchange,提问作者spyle
相关产品推荐
相关产品推荐

