Skip to content

Instantly share code, notes, and snippets.

@sundevilyang
Last active June 2, 2019 01:21
Show Gist options
  • Save sundevilyang/e91a3d82c91cdbc467a96df37c3bbac1 to your computer and use it in GitHub Desktop.
Save sundevilyang/e91a3d82c91cdbc467a96df37c3bbac1 to your computer and use it in GitHub Desktop.
Setting Up RSpec \Capybara\Factory_bot In Rails 5
[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