使用Spring时,Rails初始化器设类级变量后测试报错如何解决?
我之前也碰到过一模一样的问题!本质上是Spring的预加载缓存在搞鬼——Spring会把Rails初始化阶段的代码(包括initializers里的内容)缓存起来,当你修改了config/initializers/transaction_logger.rb之后,Spring并不会自动感知到这个变化,还是用的旧缓存里的代码,导致你的新logger设置根本没生效,所以才会出现logger is nil的委托错误,必须手动spring stop清空缓存才行。
下面给你几个靠谱的解决办法,按推荐程度排序:
1. 让Spring自动监控初始化器文件的变化(最推荐)
你可以让Spring监听config/initializers目录的修改,这样下次你改初始化器文件时,Spring会自动重启并加载新代码,不用手动执行spring stop。
只需要在项目根目录下创建(或修改)config/spring.rb,添加以下代码:
Spring.watch "config/initializers/"
这样设置后,任何initializer文件的修改都会触发Spring自动重启,完美解决缓存问题,还能保留Spring的预加载速度优势。
2. 改用懒加载方式初始化Logger(代码层面优化)
如果不想依赖Spring的配置,也可以从Transaction::Logger类本身入手,用懒加载的方式初始化logger,避免预加载时的nil问题。
修改你的Transaction::Logger类代码:
class Transaction::Logger # 用懒加载的方式获取logger,第一次调用时才初始化 def self.logger @logger ||= new("log/transations.log") end delegate :info, :warn, :debug, :error, to: :logger end
这样不管Spring有没有缓存,只要调用logger方法时,@logger如果是nil就会自动初始化,从根源上避免了委托时的nil错误。
3. 临时禁用Spring预加载(应急用)
如果只是临时测试,不想改配置或代码,可以在运行测试时直接禁用Spring:
DISABLE_SPRING=1 bundle exec rspec
这个方法虽然能解决问题,但每次测试都会重新加载整个Rails环境,启动速度会变慢,适合临时排查问题时用,不推荐长期使用。
内容的提问来源于stack exchange,提问作者Hirurg103

