And*_*vey 6 ajax rspec ruby-on-rails capybara
我的Capybara/Rspec套件中有四个测试失败(CI部署的真正问题).
最糟糕的是,这些测试间歇性地失败,并且通常仅在整个套件运行时才会进行调试.
它们都是ajax请求,要么提交远程表单,要么单击远程链接,然后是expect(page).to have_content 'My Flash Message'.
这些测试甚至在同一测试周期内间歇性地失败.例如,我有几个表现相似的模型,所以我正在迭代它们进行测试.
e.g.,
['Country', 'State', 'City'].each do |object|
let(:target) { create object.to_sym }
it 'runs my frustrating test' do
end
end
Run Code Online (Sandbox Code Playgroud)
有时国家失败,有时国家,有时一切都过去了.
我已经尝试添加wait: 30到expect语句中.我sleep 30在expect语句之前尝试过添加.我还在接受间歇性传球.
有很多信息描述了挑剔的ajax测试,但我还没有找到很多关于如何调试和修复这些问题的信息.
在我拔掉头发之前,我真的很感激任何人的建议或指点!
谢谢你们所有这些出色的回应.看到其他人已经解决了类似的问题并且我并不孤单,这很有用.
那么,有解决方案吗?
使用调试工具的建议如pry,byebug,Poltergeist的调试功能(感谢@ Jay-Ar Polidario,@ TomWalpole)有助于确认我认为我已经知道的东西 - 即,@ BM5K建议的那些功能是有效的一直在浏览器中,错误在于测试.
我尝试调整超时和重试(@ Jay-Ar Polidario,@ BM5K),虽然这些改进仍然不是一致的修复.更重要的是,这种方法感觉就像修补孔而不是正确的修复,所以我并不完全舒服.
最后,我对这些测试进行了重大改写.这需要分解多步功能,并单独设置和测试每个步骤.虽然纯粹主义者可能声称这不是从用户的角度进行真正的测试,但每次测试之间都有足够的重叠,我对结果感到满意.
在完成这个过程时,我注意到所有这些错误都与"点击事物或填写表格"有关,正如@BoraMa建议的那样.虽然在这种情况下经验被颠倒了 - 我们采用了.trigger('click')语法,因为capybara + poltergeist报告使用click_linkor 点击元素时出错find(object).click,而且这些测试都是有问题的.
为了避免这些问题,我尽可能地从测试中删除了JS.即,在没有启用JS的情况下测试大部分功能,然后创建非常短的,有针对性的JS规范来测试特定的JS响应,功能或用户反馈.
所以没有一个单独的修复.一种重要的重构,说实话,可能需要发生并且是一项有价值的练习.通过将所有内容分解为单独的测试,测试已经失去了一些功能,但总体而言,这使得测试更容易阅读和维护.
仍有一些测试偶尔显示为红色,需要更多工作.但整体上有很大改进.
感谢大家的指导,并向我保证测试环境中的交互可能是根本原因.
让我也讲讲故事吧:)。最近,我们还尝试寻找并修复在类似设置(Poltergeist、JS 测试)下间歇性失败的测试的问题。当整个测试套件运行时,测试失败的可能性比单独运行时更大,但整个套件成功的时间大约为三分之一。套件中只有几个测试(大约 10 个)随机失败,其他测试似乎一直运行正常。
首先,我们确保测试不会由于数据库截断问题、剩余记录等而失败。我们在失败时制作了屏幕截图,以验证页面看起来是否正确。
经过大量搜索后,我们注意到所有剩余的失败测试都涉及点击事物或填写表单,而页面上经常使用 jQuery 动画和其他动态操作。这让我们想到了这个恶作剧问题,它最终对我们有很大帮助。事实证明,当点击按钮或处理表单输入时,Poltergeist 会尝试最大程度地模仿普通用户,这可能会在输入/链接动画时导致问题。
认识到这对我们来说确实是一个问题的一种方法是,我们可以成功地访问find页面上的元素,但浏览器无法单击它。
我们最终使用了一个不太干净的解决方案 - 我们重写了一些水豚助手,用于在内部使用find和与表单进行单击和交互trigger:
# override capybara methods as they react badly with animations
# (click/action is not registered then and test fails)
# see https://github.com/teampoltergeist/poltergeist/issues/530
def click_button(locator, *options)
find_button(locator, *options).trigger(:click)
end
def click_link(locator, *options)
find_link(locator, *options).trigger(:click)
end
def choose(locator, *options)
find(:radio_button, locator, *options).trigger(:click)
end
def check(locator, *options)
find(:checkbox, locator, *options).trigger(:click)
end
Run Code Online (Sandbox Code Playgroud)
这种方法可能会导致一些意想不到的问题,因为现在您将能够单击测试中的内容,即使它们被模态 div 重叠或它们在页面上不完全可见。但在仔细阅读了 github 问题上的评论后,我们决定这就是我们要走的路。
从那时起,我们只有极少数的测试失败,这似乎与另一个 Poltergeist超时问题有关。但失败的情况如此罕见,以至于我们没有进一步研究的冲动——测试终于足够可靠了。
间歇性失败的测试很难排除故障,但您可以采取一些措施来让事情变得更轻松。首先是删除任何循环或共享示例。明确地陈述每个期望应该可以更清楚地表明哪个示例组合失败(或者更明显地表明它确实是随机的)。
在几次运行过程中,跟踪哪些测试失败。他们都在同一个上下文组中吗?
您是否混合并匹配了 javascript 测试和非 javascript 测试?如果是,您可能会遇到数据库问题(我见过由于在上下文块中切换数据库清理策略而导致的问题)。
确保考虑测试所在的任何父上下文块。
如果这些都不能缩小您的搜索范围,请使用允许您重试失败测试的 gem。
我过去使用过respec-retry ,但最近发现它不可靠。我已经切换到rspec-repeat。我通常在开发中保留这些(配置为 1 次尝试)并在 CI 上进行多次尝试(通常为 3 次)。这样我就可以感觉到哪些测试在本地不稳定,但不会让这些测试破坏我的构建(除非它们持续失败)。
长话短说
我遇到的大多数间歇性失败的测试都有很多变化的部分(rails、capybara、数据库清理器、工厂女孩、phantomjs、rspec 仅举几例)。如果代码经过测试并且规范经常通过并且该功能在浏览器中始终有效,那么测试环境中的某些交互可能是间歇性故障的根本原因。如果您无法找到原因,请重试失败的规范几次。