Last active
June 2, 2019 01:21
-
-
Save sundevilyang/e91a3d82c91cdbc467a96df37c3bbac1 to your computer and use it in GitHub Desktop.
Setting Up RSpec \Capybara\Factory_bot In Rails 5
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Setting Up RSpec And Capybara In Rails 5 For Testing | Tandem](https://madeintandem.com/blog/setting-up-rspec-and-capybara-in-rails-5-for-testing/) | |
RSpec是Ruby社区中一个非常受欢迎的行为驱动开发(BDD)测试框架。 | |
Capybara使我们的用户最终可以轻松地与应用程序进行交互:通过浏览器。它有一个可读的DSL和各种配置选项(我们稍后会介绍)。 | |
## 获得工具 | |
显然你会想要安装RSpec和Capybara,但是你也需要Selenium和Database Cleaner来帮助把它们放在一起。 | |
将它们添加到:test和:development您的组中Gemfile,然后bundle install: | |
``` | |
group :development, :test do | |
gem "database_cleaner" | |
gem "rspec-rails" | |
gem 'factory_bot_rails' | |
gem 'cucumber-rails', require: false | |
end | |
group :test do | |
# Adds support for Capybara system testing and selenium driver | |
gem 'capybara', '>= 2.15' | |
gem 'capybara-screenshot' | |
gem 'selenium-webdriver' | |
# Easy installation and use of chromedriver to run system tests with Chrome | |
gem 'chromedriver-helper' | |
end | |
``` | |
## 安装和配置RSpec | |
你需要运行`rails generate rspec:install`将创建 .rspec,spec/spec_helper.rb,spec/rails_helper.rb文件。 | |
#### spec_helper.rb | |
取消注释一些配置选项并删除大部分注释后,我们只剩下相当少量的配置: | |
``` | |
RSpec.configure do |config| | |
config.expect_with :rspec do |expectations| | |
expectations.include_chain_clauses_in_custom_matcher_descriptions = true | |
end | |
config.mock_with :rspec do |mocks| | |
mocks.verify_partial_doubles = true | |
end | |
config.shared_context_metadata_behavior = :apply_to_host_groups | |
config.filter_run_when_matching :focus | |
config.example_status_persistence_file_path = "spec/examples.txt" | |
config.disable_monkey_patching! | |
config.default_formatter = 'doc' if config.files_to_run.one? | |
config.order = :random | |
Kernel.srand config.seed | |
# config.profile_examples = 10 | |
end | |
``` | |
强烈建议您阅读所有这些评论,以便更好地了解每个选项的作用。虽然我想提出一些特别重要的内容(注意:这些选项对于帖子的其余部分并不重要。)。 | |
`mocks.verify_partial_doubles = true` 阻止您存根对象上尚未存在的任何方法。换句话说,它有助于打破你的模拟错误。 | |
`config.disable_monkey_patching!` 防止从RSpec的猴子打补丁 should和 stub在几乎一切。这使得您的对象在您的测试中表现得像在“真实”生活中一样。 | |
`config.order = :random` 和 `Kernel.srand config.seed` 确保每次运行时测试都以随机顺序运行。这有助于保持每个测试彼此独立,确保它们不会意外地依赖于彼此的副作用。 | |
我还留下了config.profile_examples评论,因为尽管让它运行以确定减慢你的套件速度的测试真的很有帮助,但它的额外控制台输出会有点吵。 | |
#### rails_helper.rb | |
在取消注释某些配置选项并删除大部分注释后,我们再次进行了相当少量的配置: | |
``` | |
ENV["RAILS_ENV"] ||= "test" | |
require File.expand_path("../../config/environment", __FILE__) | |
abort("The Rails environment is running in production mode!") if Rails.env.production? | |
require "spec_helper" | |
require "rspec/rails" | |
# Add additional requires below this line. Rails is not loaded until this point! | |
# Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } | |
ActiveRecord::Migration.maintain_test_schema! | |
RSpec.configure do |config| | |
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures | |
config.fixture_path = "#{::Rails.root}/spec/fixtures" | |
config.use_transactional_fixtures = true | |
config.infer_spec_type_from_file_location! | |
config.filter_rails_from_backtrace! | |
end | |
``` | |
唯一要更改的默认值是config.use_transactional_fixtures从true到false。这会阻止RSpec Rails将我们的测试包装在数据库事务中,这意味着,目前为一次测试创建的记录将在下一次测试中可见。不过不用担心,您将有数据库清理工具尽快管理我们的交易。首先,我们将设置Capybara。 | |
## 设置Capybara | |
Capybara很容易添加到RSpec。只需添加`require "capybara/rspec"`到require您的rails_helper.rb列表中即可。 | |
默认情况下,Capybara使用RackTest驱动程序来测试您的应用程序。它速度非常快,但它不会运行您的JavaScript,所以如果您希望您的功能测试确保您的JavaScript正常工作,您需要通过传递js: true给标记测试describe: | |
``` | |
RSpec.describe "Signing in", js: true do | |
# tests that actually execute JavaScript | |
end | |
``` | |
Selenium是JavaScript测试的默认驱动程序,这就是我们包含selenium-webdrivergem的原因。默认情况下,Selenium将使用Firefox,但某些版本与Selenium不兼容。如果您想使用Chrome,可以通过在以下位置添加以下内容来覆盖它rails_helper.rb: | |
``` | |
Capybara.register_driver :selenium_chrome do |app| | |
Capybara::Selenium::Driver.new(app, browser: :chrome) | |
end | |
Capybara.javascript_driver = :selenium_chrome | |
``` | |
注意:要使用Chrome,您需要安装ChromeDriver,如果您安装了Homebrew,则只需安装`brew install chromedriver`。 | |
## 为什么使用 Database Cleaner? | |
下面的设置起初可能看起来有些奇怪,但它是为了解决一个特定且相当难以诊断的问题:当`js:true` 的Capybara测试对 transactions很困难。更具体地说,Capybara spins up 我们的Rails应用程序的一个实例,它无法看到我们的测试数据事务,所以即使我们在测试中创建了一个用户,登录也会因为Capybara运行我们rails应用程序实例而失败,因为没有用户。更简单地说,这意味着Capybara将无法“看到”我们的测试数据库记录。 | |
一种解决方案是放弃js: true测试,但仅此一项是不够的。您的js: true测试将取决于常见的设置,并且必须按特定顺序运行,将它们耦合在一起并使问题难以调试。 | |
更好的方法是将大部分测试包装在事务中,并对我们的js: true测试使用截断。database cleanup程序使这很容易。 | |
## 集成database cleanup | |
首先,首先通过在 RSpec.configure 块中添加以下内容来确保我们的测试以干净的平板开始: | |
``` | |
config.before(:suite) do | |
DatabaseCleaner.clean_with(:truncation) | |
end | |
``` | |
现在我们需要告诉Database Cleaner如何管理数据库以进行常规测试和Selenium测试: | |
``` | |
config.before(:each) do | |
DatabaseCleaner.strategy = :transaction | |
end | |
config.before(:each, js: true) do | |
DatabaseCleaner.strategy = :truncation | |
end | |
``` | |
这些块的顺序非常重要。现在我们的js: true块在规范时会覆盖普通的块js: true。如果它被颠倒过来,数据库清理程序将始终使用事务,因为我们的js: true测试无法看到这些记录会出现问题。接下来我们必须实际清理数据库: | |
``` | |
# This block must be here, do not combine with the other `before(:each)` block. | |
# This makes it so Capybara can see the database. | |
config.before(:each) do | |
DatabaseCleaner.start | |
end | |
config.after(:each) do | |
DatabaseCleaner.clean | |
end | |
``` | |
您可能希望将before(:each)我们刚刚添加的内容与前一个相结合,但不是。如果将它们组合在一起,Database Cleaner将在设置为使用截断之前打开一个事务,这意味着Capybara将无法“看到”测试数据库记录。 | |
所以现在你rails_helper.rb应该看起来像: | |
``` | |
ENV["RAILS_ENV"] ||= "test" | |
require File.expand_path("../../config/environment", __FILE__) | |
abort("The Rails environment is running in production mode!") if Rails.env.production? | |
require "spec_helper" | |
require "rspec/rails" | |
# Add additional requires below this line. Rails is not loaded until this point! | |
require "capybara/rspec" | |
# Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } | |
ActiveRecord::Migration.maintain_test_schema! | |
Capybara.register_driver :selenium_chrome do |app| | |
Capybara::Selenium::Driver.new(app, browser: :chrome) | |
end | |
Capybara.javascript_driver = :selenium_chrome | |
RSpec.configure do |config| | |
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures | |
config.fixture_path = "#{::Rails.root}/spec/fixtures" | |
config.use_transactional_fixtures = false | |
config.infer_spec_type_from_file_location! | |
config.filter_rails_from_backtrace! | |
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 | |
# This block must be here, do not combine with the other `before(:each)` block. | |
# This makes it so Capybara can see the database. | |
config.before(:each) do | |
DatabaseCleaner.start | |
end | |
config.after(:each) do | |
DatabaseCleaner.clean | |
end | |
end | |
``` | |
再次确保您的config.before(:each)块(无论它们是否js: true存在)都在上面的顺序中。 | |
现在,当您运行测试时,您将没有任何共享数据库状态,并且Capybara将能够“看到”它能够“看到”所需的一切。另外,您可以按随机顺序运行它们,没有任何问题。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment