Ruby on Rails集成测试期间出现间歇性的ActiveRecord :: RecordNotFound错误

7
我有一些集成测试会间歇性地失败,总是出现ActiveRecord::RecordNotFound错误。 错误发生在控制器内,在给定固件ID的情况下进行了一个find调用。虽然它在多个控制器中都会出现,但我在浏览站点时从未看到过这种行为,但我会说测试会在30-50%的时间内失败。重新运行测试似乎可以解决问题。

如果我手动将固件加载到开发数据库中,则似乎找不到的ID确实存在于表中。

我还没有找到许多关于遇到相同问题的人的信息...有什么想法吗?

更新:以下是test_helper.rb的内容

ENV["RAILS_ENV"] = "test"
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require 'capybara/rails'
class ActiveSupport::TestCase
  # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
  #
  # Note: You'll currently still have to declare fixtures explicitly in integration tests
  # -- they do not yet inherit this setting
  fixtures :all
  # Add more helper methods to be used by all tests here...
end
# Transactional fixtures do not work with Selenium tests, because Capybara
# uses a separate server thread, which the transactions would be hidden
# from. We hence use DatabaseCleaner to truncate our test database.
DatabaseCleaner.strategy = :truncation
class ActionDispatch::IntegrationTest
  # Make the Capybara DSL available in all integration tests
  include Capybara::DSL
  # Make the Capybara Email DSL available in all integration tests
  include Capybara::Email::DSL
  # Stop ActiveRecord from wrapping tests in transactions
  self.use_transactional_fixtures = false
  # Switch to selenium as the default driver for JS support
  Capybara.default_driver = :selenium
  # Only click on visible links!
  Capybara.ignore_hidden_elements = true
  teardown do
    DatabaseCleaner.clean       # Truncate the database
    Capybara.reset_sessions!    # Forget the (simulated) browser state
    Capybara.use_default_driver # Revert Capybara.current_driver to Capybara.default_driver
  end
end

更新以下是连续运行相同测试5次的结果。我运行了这些测试,等待它们完成,然后立即使用命令rails test:integration再次运行它们。注意:在测试中始终存在的E和F实际上是测试错误-我正在修复这些错误。例如,第二个测试运行是“正确”的,但第一个显示了虚假的错误。

..E......E..........F.
.........E..........F.
..E......E..........F.
..E......E..........F.
..E....E.E..........F.

错误确实发生在两个不同的表中--它们并不试图查找相同的记录。但似乎只有一部分测试存在这个问题...

更新 这是测试结果中实际错误的样子:

  1) Error:
test_browsing_user_snops(BrowseStoriesTest):
ActiveRecord::RecordNotFound: Couldn't find User with id=980190962
    /home/myuser/.rvm/gems/ruby-1.9.3-p286/gems/activerecord-3.2.9/lib/active_record/relation/finder_methods.rb:341:in `find_one'
    /home/myuser/.rvm/gems/ruby-1.9.3-p286/gems/activerecord-3.2.9/lib/active_record/relation/finder_methods.rb:312:in `find_with_ids'
    /home/myuser/.rvm/gems/ruby-1.9.3-p286/gems/activerecord-3.2.9/lib/active_record/relation/finder_methods.rb:107:in `find'
    /home/myuser/.rvm/gems/ruby-1.9.3-p286/gems/activerecord-3.2.9/lib/active_record/querying.rb:5:in `find'
    /home/myuser/Projects/myproject/app/controllers/users_controller.rb:18:in `show'
    ...

请注意,当控制器尝试查找记录时,错误会出现。相关的代码行实际上是@user = User.find(params[:id])。这种情况也会发生在其他模型中,不仅仅是用户控制器和用户模型。


2
你是为每个测试重新建立整个集成测试环境,还是只在开始时建立一次,或者按规范进行?(当你说集成测试时,你是指典型的Rails全栈“单元”测试吗 - 是的,按照正常标准,它们根本不是单元测试 - 还是你已经费尽心思隔离了所有内容,并拥有真正的单元测试和集成测试环境? - cfeduke
1
我从未见过这种情况,快速搜索谷歌也表明其他人也没有。当你说“间歇性”时,是指“总是在不同的地方失败”,还是“有时工作,有时失败”,如果是后者,“总是在相同的测试中”或“看似随机”?如果故障看似随机,则表明存在一些时间问题,例如数据保存到数据库,但可能在下一个测试命令发出时尚未提交。那似乎不太可能。是哪个数据库?还有其他模式吗? - Tom Harrison
@tharrison 在这里 intermittent 的意思是指,在测试列表中有些集成测试有时会通过,而有时会失败。错误总是一个 RecordNotFound 错误。有时只有一个失败并带有 RecordNotFound,有时会有一堆失败的测试用例。测试环境中的数据库是 SQLite。我正在使用 Capybara 进行集成测试,或许这与此有关? - aardvarkk
@cfeduke 我听说过FactoryGirl。下次我会试试看。我认为由于调用fixtures:all,每个文本中的固定装置都是可用的,但我可能错了。我只是通过像amodel(:one)这样做来在集成测试中访问它们,其中amodel在固定装置文件夹中有一个相应的amodel.yml文件。理论上我可以切换到MySQL或PostgreSQL。现在只是开发而已。PostgreSQL比MySQL更好的特别原因吗?当我开始学习Rails时,我读到的东西推荐使用MySQL作为默认值。 - aardvarkk
@aardvarkk 先不要担心PostgreSQL和MySQL的区别,等一切都正常运行后再考虑 :) (MySQL的设置时间非常快,对于大多数项目来说是一个不错的选择;PostgreSQL是一个更强大的关系型数据库管理系统,如果你想要部署到Heroku,你需要在本地使用PostgreSQL进行开发,所以两者都有优缺点) - cfeduke
显示剩余10条评论
1个回答

5
我担心在截断数据和Capybara驱动Web浏览器的速度之间可能会有延迟,这有时可能会导致身份列值从意外值开始(例如,对于记录#1为7,而不是您期望的1,因为该身份生成器尚未重置)。我没有证据表明这是事实,但这是我最好的猜测。
请查看此网址上第3个项目:http://blog.plataformatec.com.br/2011/12/three-tips-to-improve-the-performance-of-your-test-suite/。这是一个非常简单的技巧,将use_transactional_fixtures设置为true,并通过将该代码粘贴到您的test_helper.rb中来打猴子补丁ActiveRecord。这可以帮助消除任何潜在问题的间歇性磁盘IO问题。
另一件您可以尝试的事情是通过在database.yml文件中将该数据库的文件名设置为:memory:来限制SQLite测试数据库。这应该完成与上述相同的任务-消除可能导致这些间歇性问题的杂波磁盘IO。

我认为你在这方面有所发现。到目前为止,我已经两次使用use_transactional_features设置运行了整个测试套件,并且两次都得到了相同的(非常不同 - 更多失败!)结果。因此至少它是可重复的!以前通过的东西现在失败了,但似乎失败总是相同的。我会再运行几次以确保,然后答案就归你了 :) - aardvarkk
我并不理解为什么这个设置会有问题,但无论如何! - aardvarkk
是的——现在一堆新东西都出问题了(...?!),但至少结果是可重复的。至少这是一个开始吧。不确定是否应该将此报告为错误?我甚至不知道正在发生什么... - aardvarkk
非常感谢您的辛勤工作和关注!我真的很感激。 - aardvarkk
2
我会直接切入主题,为您节省大量时间:http://pryrepl.org/ - 安装它,设置您的 rails c 使用它,然后在测试中您可以使用 binding.pry,它将进入一个 pry 会话,您可以使用 lscd some_variable 来检查值;您甚至可以运行 ActiveRecord 查询(User.find_by_email(...))来查看数据库此时实际上有什么。 - cfeduke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接