如何使这些测试可靠地通过?
目前这些测试很不稳定。
有时他们会过去。有时他们会失败。
下面是演示此问题的设置、代码和输出。
克服这个问题的建议将不胜感激,我相信也会帮助许多其他人,所以请发表评论!
测试代码环境
- 轨道3.2
- RSpec 2.x
- 水豚
- 恶作剧鬼
- PhantomJS
- AngularJS
- 谷歌浏览器版本 47.0.2526.106(64 位)
从 Gemfile.lock 测试 Gem
capybara (2.1.0)
database_cleaner (0.7.1)
debug_inspector (0.0.2)
guard-bundler (0.1.3)
guard-livereload (1.2.0)
guard-rspec (2.1.2)
jasminerice (0.0.10)
pg (0.17.1)
phantomjs (2.1.1.0)
poltergeist (1.4.1)
protractor-rails (0.0.17)
pry (0.9.12)
rack (1.4.7)
rack-test (0.6.3)
rails (3.2.21)
rails-assets-angular (1.3.20)
rspec-rails (2.11.4)
simplecov (0.8.2)
sprockets (2.2.3)
zeus (0.13.3)
zeus-parallel_tests (0.2.1)
我尝试过的事情
- 确保我使用 Capybara 的等待 DSL 匹配器
- 确保我的数据库清理器设置正确
- 测试每个页面项目,假设它可能不在页面上并且仍然可以加载
- 缩小不一致的测试范围
- 单独运行不一致的测试
-
识别触发不一致测试结果的 Capybara DSL 代码。
- 即创建一条新记录并假设页面已重定向并且该记录位于页面 click_on 上
or
- 将 Capybara 升级到最新版本(在单独的分支中)
- 将 Poltergeist 和 RSpec 升级到最新版本(在单独的分支中,仍在处理此问题)
我使用的资源
[1] 水豚 DSL https://github.com/jnicklas/capybara#the-dsl
[2] Capybara、PhantomJs、Poltergeist 和 Rspec 提示 http://www.railsonmaui.com/tips/rails/capybara-phantomjs-poltergeist-rspec-rails-tips.html
还有很多...
测试是如何进行的
rspec spec/integration/costings/show_costing_spec.rb --format documentation
测试代码
show_costing_spec.rb
require "spec_helper"
RSpec.describe "Show a new costing in the listing," do
before :each do
admin_sign_in
create_costing("test1")
end
it "shows the costing after creation" do
within "#costings_table" do
expect(page).to have_css("#name", text: "test1")
end
end
it "shows the details of the new costing after creation" do
expect(page).to have_content("Costings")
within "#costings_table" do
expect(page).to have_content("test1")
all("#show").last.click
end
expect(page).to have_content("Costing Details")
expect(page).to have_css("#name", text: "test1")
end
end
spec_helper.rb
# This file is copied to spec/ when you run 'rails generate r spec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
# Add library functions here so we can test them.
require File.expand_path(File.dirname(__FILE__) + "/../lib/general")
require 'rspec/rails'
require 'rspec/autorun'
# Integration Testing
require 'capybara/poltergeist'
Capybara.register_driver :poltergeist_debug do |app|
Capybara::Poltergeist::Driver.new(app, :inspector => true)
end
Capybara.javascript_driver = :poltergeist_debug
Capybara.default_driver = :poltergeist_debug
# Capybara Integration Test Helpers
def admin_sign_in
visit "/login"
#Create staff member in database
Staff.make!(:admin)
#Log In
fill_in "staff_username", with: "adminstaff"
fill_in "staff_password", with: "password"
click_button "login"
end
def create_costing(item)
visit "/api#/costings"
click_on "new_btn"
within "#form_costing" do
find("#name", match: :first).set("#{item}")
find("#description", match: :first).set("test description")
find("#from_date", match: :first).set("15/02/2016")
find("#cost_hourly_cents", match: :first).set("1.00")
click_on "create_btn"
end
end
RSpec.configure do |config|
config.before(:suite) do
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
require File.expand_path(File.dirname(__FILE__) + "/support/blueprints")
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
end
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# Allow a 'focus' tag so that we can run just a few tests which we are currently working on
config.treat_symbols_as_metadata_keys_with_true_values = true
config.filter_run focus: true
config.run_all_when_everything_filtered = true
config.filter_run_excluding :slow unless ENV["SLOW_SPECS"]
# Defer Garbage Collection
config.before(:all) { DeferredGarbageCollection.start }
config.after(:all) { DeferredGarbageCollection.reconsider }
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = false
# config.infer_spec_type_from_file_location!
# Configure Database Cleaner
config.include Capybara::DSL
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
检测结果
Test Run 1: Failing
运行选项:
包括 {:focus=>true}
排除 {:slow=>true}
所有的例子都被过滤掉了;忽略 {:focus=>true}
在列表中显示新的成本计算,
显示创建后的成本核算
显示创建后新成本核算的详细信息(失败 - 1)
失败:
1) 在列表中显示新的成本计算,
显示创建后新成本核算的详细信息
失败/错误:expect(page).to have_content("test1")
预期 #has_content?("test1") 返回 true,结果为 false
# ./spec/integration/costings/show_costing_spec.rb:20:in 块(3 个级别)中
# ./spec/integration/costings/show_costing_spec.rb:19:in 块(2 级)中
5.46秒完成
2个例子,1个失败
Test Run 2: Passing
运行选项:
包括 {:focus=>true}
排除 {:slow=>true}
所有的例子都被过滤掉了;忽略 {:focus=>true}
在列表中显示新的成本计算,
显示创建后的成本核算
显示创建后新成本核算的详细信息
3.57秒完成
2 个示例,0 次失败
Update 1
将测试gem升级到以下版本:
水豚 (2.6.2) 来自 (2.1.0)
来自 (0.7.1) 的数据库清理器 (1.5.1)
调试检查器 (0.0.2)
防护捆绑器 (0.1.3)
守卫-livereload (1.2.0)
防护规格 (2.1.2)
茉莉花 (0.0.10)
场均 (0.17.1)
phantomjs (2.1.1.0)
恶作剧鬼 (1.9.0) 来自 (1.4.1)
量角器导轨 (0.0.17)
从 (0.9.12) 撬出 (0.10.3)
机架 (1.4.7)
机架测试 (0.6.3)
导轨 (3.2.21)
轨道资产角度(1.4.9)来自(1.3.20)
rspec-rails (3.4.2) 来自 (2.11.4)
simplecov (0.8.2)
链轮 (2.2.3)
宙斯 (0.13.3)
zeus-parallel_tests (0.2.1)
Result 1
不幸的是,升级这些宝石似乎并没有产生什么影响,而且我的测试仍然不稳定。
Update 2
我实施了汤姆·沃波尔的建议。确保我的 admin_sign_in 等待 Sign_in 完成。
还按照汤姆的建议更新了我的database_cleaner设置。
Result 2
对于我的堆栈来说,这些更改似乎没有效果。
Note:如果不使用 AngularJS,我觉得这些改变会产生影响。谢谢汤姆的建议。
Update 3
我需要获得有关测试运行期间发生的情况的更多信息。网上有一些建议来记录、使用屏幕截图保存宝石等,但我不觉得这些是最省时的。我想指定测试在哪里暂停并查看变量和表单字段的内容。在浏览器中是理想的选择。
我用过什么
我使用“save_and_open_page”和“print page.html”进行调试。
我搬到了什么地方
当我运行 RSpec 3.4.2 时,我添加了一个调试帮助器方法:
Rails_helper.rb
def debugit
puts current_url
require 'pry'
binding.pry
end
Result 3
URL 将打印在控制台中,并且测试将暂停。在此阶段,我将能够导航到 URL、登录、导航到测试页面并查看 Capybara 测试已完成的操作。
这使我能够确定问题的根源是在使用水豚的 fill_in DSL 进行测试时出现的。
在某些测试运行中,字段将被正确填充并且表单将被提交。
在另一种情况下,表单将被正确填写,但提交按钮会被点击得太快。这里的结果是创建了一条记录,但名称和描述的输入字段未保留。
Update 4
我发现因为我使用的是 AngularJS 输入表单和表格,所以 AngularJS 需要一点时间来绑定到输入字段。如果这次不允许,则不会保存输入数据。
Capybara提供了“within”、“find”等等待方法。我使用了这些,但它们对解决 AngularJS 绑定时间问题没有帮助。
我发现 ng-if 可以用来创建一个 if 语句来等待特定项目,该项目将表示 AngularJS 与表单字段的绑定完成。
所以我使用 Capybara 等待方法来等待我想要填充的字段,并使用 AngularJS 的 ng-if 在字段准备好之前不显示字段。
执行
索引.html.erb
<div ng-if="tableParams.data">
<table id="costings_table ng-table="tableParams" class="table">
<td id="field1">{{table.field1}}</td>
<td id="field2">{{table.field2}}</td>
</table>
</div>
Result 4
测试终于通过了!然而,我拥有所有这些带有 xpath 的查找方法,确保等待特定且难以定位的项目...
Update 5
尽管在我的 gemfile 中我运行的是 gem phantomJS 版本 2.1.1,但我的命令行版本仅为 1.X。事实证明这意义重大。
我将命令行 phantomJS 版本更新为 2.1.1。同时,我确保所有输入框、按钮、表格、标题都有唯一的 ID。然后我能够删除所有 find(:xpath) 出现而不会破坏测试。
Result 5
这套测试现在一直可靠地通过!正是我想要的!是的!