使用 AJAX 请求在 Cucumber 中自动加载相关的竞争条件
Posted
技术标签:
【中文标题】使用 AJAX 请求在 Cucumber 中自动加载相关的竞争条件【英文标题】:Autoload related race condition in Cucumber with AJAX requests 【发布时间】:2014-09-13 22:39:11 【问题描述】:我将 Cucumber 与 capybara-webkit 一起用于我的应用程序在 Ruby 2.0.0、Rails 4.1 上的集成测试。我的黄瓜测试套件中的一些测试意外地开始吐出如下错误:
Circular dependency detected while autoloading constant UiValidators::ParameterFinder (RuntimeError)
/Users/kingp/.rvm/gems/ruby-2.0.0-p451@triquest/gems/activesupport-4.1.1/lib/active_support/dependencies.rb:484:in `load_missing_constant'
/Users/kingp/.rvm/gems/ruby-2.0.0-p451@triquest/gems/activesupport-4.1.1/lib/active_support/dependencies.rb:180:in `const_missing'
/Users/kingp/Projects/rails-triquest/app/controllers/contacts_controller.rb:2:in `<class:ContactsController>'
/Users/kingp/Projects/rails-triquest/app/controllers/contacts_controller.rb:1:in `<top (required)>'
/Users/kingp/.rvm/gems/ruby-2.0.0-p451@triquest/gems/activesupport-4.1.1/lib/active_support/dependencies.rb:247:in `require'
...
错误说是“循环依赖”,但它实际上是在 Rails 自动加载器尝试加载一个已经在其加载常量集中的常量时抛出的。通常这确实是由于循环依赖,但我很确定我的应用程序不是这种情况。带有崩溃测试的分支和我从中分叉的稳定分支之间的差异表明,唯一的变化是对咖啡脚本文件、视图模板、迁移和我正在编写的新黄瓜功能。我没有接触任何控制器或模型代码。
我最终在 Rails 自动加载器中插入了一些日志记录代码,以帮助我弄清楚发生了什么:
# Inserted at activesupport-4.1.1/lib/active_support/dependencies.rb:467
_thread_id_for_debug = Thread.current.object_id
STDERR.puts "*** #loaded.count #from_mod #const_name - #_thread_id_for_debug"
loaded
是一组自动加载代码文件的路径,from_mod
是请求来自的上下文,const_name
是我们试图加载的常量。这一切最终让我在崩溃之前得到了这个:
*** 104 Object SitesController - 70180261360940
*** 105 Object ContactsController - 70180240113760
*** 105 SitesController UiValidators - 70180261360940
*** 105 Object UiValidators - 70180261360940
*** 105 UiValidators ParameterFinder - 70180261360940
*** 107 UiValidators ParameterFinder - 70180240113760
看起来两个线程正在尝试自动加载相同的常量。我的猜测是常量的名称在第一个线程完成加载之前被添加到 Rails 的“加载”常量集中。第二个线程无法解析常量(因为加载尚未完成),要求自动加载器找到它,当自动加载器在其“已加载”集中看到常量时会引发。
在测试的这一点上,两个控制器(SitesController 和 ContactsController)正在响应 AJAX 请求,几乎同时启动。
我找到了一种解决崩溃的方法,只需在 AJAX 之前包含对模块 UiValidators::ParameterFinder
的引用。但这似乎很脆弱,也不是很优雅。除了开启测试环境的Eager Loading,有没有其他方法可以避免这个问题?
【问题讨论】:
我遇到了同样的问题。打开 eager_load 甚至没有为我修复它.. 不明白为什么不这样做,因为它不应该在启用该功能的情况下尝试自动加载?仍在调试.. 【参考方案1】:我遇到了同样的问题(没有 Cucumber,只有 Capybara 和 Poltergeist)。设置config.eager_load = true
甚至对我都不起作用(不太明白为什么不……)。
我最终使用了Spring 并且从那以后没有出现循环依赖错误。
【讨论】:
【参考方案2】:在使用 Sidekiq 时,Rails 4.1.4 也有同样的问题。我假设当调用 active_support 内的const_missing
时,线程化的 Sidekiq 工作人员内部的竞争条件会导致各种问题。
除了确保我当前的环境将执行即时加载,即通过config.eager_load = true
,我还必须将我的工作人员正在使用的所有组件从lib
目录添加到config.eager_load_paths
(通过config.eager_load_paths += %W(#config.root/lib)
内@ 987654326@).
这是必要的,因为我假设设置 config.eager_load = true
只会使 Rails 急切加载 app/
目录的内容。
App::Application.config.eager_load_paths
=> [
[0] "/home/archive/releases/20140721180504/app/assets",
[1] "/home/archive/releases/20140721180504/app/controllers",
[2] "/home/archive/releases/20140721180504/app/helpers",
[3] "/home/archive/releases/20140721180504/app/mailers",
[4] "/home/archive/releases/20140721180504/app/models",
[5] "/home/archive/releases/20140721180504/app/services",
[6] "/home/archive/releases/20140721180504/app/workers"
]
两者的结合似乎有助于解决这个问题。
【讨论】:
以上是关于使用 AJAX 请求在 Cucumber 中自动加载相关的竞争条件的主要内容,如果未能解决你的问题,请参考以下文章
Rails Cucumber使用Capybara测试AJAX
如何使用 Frank Cucumber 自动进行滑动/滚动手势?