使用 DatabaseCleaner 和事务进行片状测试。如何调试?
Flaky tests with DatabaseCleaner and transactions. How to debug?
我有一个 feature/integration 规范,运行 贯穿整个用户流程。在该用户流程结束时,应用程序中的一个页面将显示我的 Postgres 数据库中的几条记录。当我 运行 测试本身时,它通过了。自从 selenium 驱动程序打开 firefox 以来,我可以通过各个步骤看到它正确保存:Capybara.current_driver = :selenium
。然而,这个规范经常失败,几乎可以预见,当它在一堆控制器规范之后 运行 时。在那些控制器规范中,我正在做的唯一有趣的事情是 运行 启用此登录功能:
module DeviseMacros
def login_user
before(:each) do
@request.env['devise.mapping'] = Devise.mappings[:user]
user = create(:user_with_active_account)
sign_in user
end
end
end
所以我这样称呼它:
describe AwesomeController do
login_user
it 'responds with 200' do
get :new
expect(response.status).to eq 200
end
end
当 运行 在控制器规范之后,我可以立即看到测试将失败,因为某些 UI 元素应该根据数据库中的内容出现,但显然它们不存在。
我的DatabaseCleaner策略如下:
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, js: true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
通过反复试验我改变了
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
到
config.before(:each) do
DatabaseCleaner.strategy = :truncation
end
walla,它过去了。当然,现在测试套件占用的时间是原来的 2 倍多。
我已经用 js: true
标记了我所有的 :selenium
测试,以确保 :truncation
用于它们,但这真的无关紧要,因为 :selenium
已经驾驶那些。然而,最重要的是,这个功能规范在那些控制器规范之后仍然失败。
我还应该去哪里找?我该如何进行调试?
我这里唯一可能相关的其他独特的东西是:
# In spec/support/shared_db_connection.rb
# https://gist.github.com/josevalim/470808
class ActiveRecord::Base
mattr_accessor :shared_connection
@@shared_connection = nil
def self.connection
@@shared_connection || retrieve_connection
end
end
# Forces all threads to share the same connection. This works on
# Capybara because it starts the web server in a thread.
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
任何关于如何进行调试的建议或想法将不胜感激。
如果您有任何其他问题,请提出。谢谢
更新:2016 年 6 月 1 日
导致失败的确切代码行是:
module DeviseMacros
def login_user
before(:each) do
@request.env['devise.mapping'] = Devise.mappings[:user]
user = create(:user_with_active_account)
sign_in user # <----- THIS GUY RIGHT HERE! When removed, the ControllerSpec fails but the integration test passes.
end
end
end
因此,出于某种原因,使用此控制器规范(使用 :transaction
策略)访问数据库似乎会影响功能规范(使用 :truncation
策略)。
我正在讨论在尝试对设计用户进行身份验证时根本不在控制器规范中访问数据库,这对我来说很酷,但我觉得不应该那样做。如果我确实希望能够使用 sign_in
方法,关于如何进行的任何想法?
谢谢
删除共享连接 hack,因为它导致的问题多于它的价值,并将您的数据库清理器配置更新为数据库清理器自述文件中推荐的配置 - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example
我有一个 feature/integration 规范,运行 贯穿整个用户流程。在该用户流程结束时,应用程序中的一个页面将显示我的 Postgres 数据库中的几条记录。当我 运行 测试本身时,它通过了。自从 selenium 驱动程序打开 firefox 以来,我可以通过各个步骤看到它正确保存:Capybara.current_driver = :selenium
。然而,这个规范经常失败,几乎可以预见,当它在一堆控制器规范之后 运行 时。在那些控制器规范中,我正在做的唯一有趣的事情是 运行 启用此登录功能:
module DeviseMacros
def login_user
before(:each) do
@request.env['devise.mapping'] = Devise.mappings[:user]
user = create(:user_with_active_account)
sign_in user
end
end
end
所以我这样称呼它:
describe AwesomeController do
login_user
it 'responds with 200' do
get :new
expect(response.status).to eq 200
end
end
当 运行 在控制器规范之后,我可以立即看到测试将失败,因为某些 UI 元素应该根据数据库中的内容出现,但显然它们不存在。
我的DatabaseCleaner策略如下:
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, js: true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
通过反复试验我改变了
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
到
config.before(:each) do
DatabaseCleaner.strategy = :truncation
end
walla,它过去了。当然,现在测试套件占用的时间是原来的 2 倍多。
我已经用 js: true
标记了我所有的 :selenium
测试,以确保 :truncation
用于它们,但这真的无关紧要,因为 :selenium
已经驾驶那些。然而,最重要的是,这个功能规范在那些控制器规范之后仍然失败。
我还应该去哪里找?我该如何进行调试?
我这里唯一可能相关的其他独特的东西是:
# In spec/support/shared_db_connection.rb
# https://gist.github.com/josevalim/470808
class ActiveRecord::Base
mattr_accessor :shared_connection
@@shared_connection = nil
def self.connection
@@shared_connection || retrieve_connection
end
end
# Forces all threads to share the same connection. This works on
# Capybara because it starts the web server in a thread.
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
任何关于如何进行调试的建议或想法将不胜感激。
如果您有任何其他问题,请提出。谢谢
更新:2016 年 6 月 1 日
导致失败的确切代码行是:
module DeviseMacros
def login_user
before(:each) do
@request.env['devise.mapping'] = Devise.mappings[:user]
user = create(:user_with_active_account)
sign_in user # <----- THIS GUY RIGHT HERE! When removed, the ControllerSpec fails but the integration test passes.
end
end
end
因此,出于某种原因,使用此控制器规范(使用 :transaction
策略)访问数据库似乎会影响功能规范(使用 :truncation
策略)。
我正在讨论在尝试对设计用户进行身份验证时根本不在控制器规范中访问数据库,这对我来说很酷,但我觉得不应该那样做。如果我确实希望能够使用 sign_in
方法,关于如何进行的任何想法?
谢谢
删除共享连接 hack,因为它导致的问题多于它的价值,并将您的数据库清理器配置更新为数据库清理器自述文件中推荐的配置 - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example