rails-test-pipeline
provides a structure for setting up automated tests using RSpec and MiniTest for rails on github.
$ rails new my-rails-app --database=postgresql
$ cd my-rails-app
$ rails db:create
$ git add .
$ git commit -m "rails new"
$ gh repo create
$ git push origin master
Follow the rspec documentation to add and install the rspec gem rspec/rspec-rails
# Gemfile
group :development, :test do
gem 'rspec-rails', '~> 5.0.0'
end
$ bundle install
$ rails generate rspec:install
$ rails db:migrate && rails db:test:prepare
Install the launchy gem In Gemfile
group :test do
# [...]
gem 'launchy'
end
$ bundle install
In test/test_helper.rb
include and capybara headless chrome
for imitating user behaviour without opening a browser. There are several additional helpers like e.g. devise warden
(for testing applications with login functionality), which you might add later.
class ActiveSupport::TestCase
# [...]
end
Capybara.register_driver :headless_chrome do |app|
options = Selenium::WebDriver::Chrome::Options.new(args: %w[no-sandbox headless disable-gpu window-size=1400,900])
Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end
Capybara.save_path = Rails.root.join('tmp/capybara')
Capybara.javascript_driver = :headless_chrome
Set up Browser tests in test/application_system_test_case.rb
require "test_helper"
# Make sure drivers dont fail under parallel testing
Webdrivers::Chromedriver.update
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :headless_chrome # Update this line
end
Make Debugging easier by adding config/environments/test.rb
Rails.application.configure do
# [ ... ]
config.action_dispatch.show_exceptions = true # Update this line
# [ ... ]
end
Github Actions will build a test environment and run unit/system tests on every push or pull request.
- Add the file
.github/workflows/test.yml
in root directory and copy the script to build and run tests from here - Make sure you have your ruby version defined in
.ruby-version
. In this example its2.6.6
- Add the file
config/database.github.yml
in root directory and copy config for the test database environment from here. - Optional - Make passing all tests mandatory in order to merge code into master: In your repo go to
Settings/Branches
andAdd rule
and activateRequire status checks to pass before merging
as well as yourtest
.
The Github Action will automatically run unit tests with $ bundle exec rspec
and system tests with $ bundle exec rails test:system
. Lets write some tests.
Write unit tests with RSpec to test your models.
As an example lets build the model Tree
$ rails g model Tree age:integer # automatically creates spec/models/tree_spec.rb
$ rails db:migrate
Lets write a simple test for creating a Tree
instance and its age
accessor. In spec/models/tree_spec.rb
write
require 'rails_helper'
describe Tree, type: :model do
it 'creates a Tree instance with an age' do
tree = Tree.new(age: 13)
expect(tree.age).to eq(13)
end
end
Learn more about Rspec. Learn more about how to write good tests
Use System/Integration tests to imitate the core user journey. We are using MiniTest which is included in Rails by default. Keep the amount of system tests low as they are very time costly. We are
Lets take our Tree
example from above and create a new system test
$ rails g system_test tree
System tests require an own environment that has a different database than local and production database. Therefore we set up a testing database called fixtures
. We can quickly write them in yml in test/fixtures/trees.yml
:
apple_tree:
age: 13
pear_tree:
age: 10
Write a test in test/system/products_test.rb
to test the display of a tree's age in the trees_path
require "application_system_test_case"
class ProductsTest < ApplicationSystemTestCase
test "visit home page and see headline" do
visit trees_path
save_and_open_screenshot # only works with launchy and opens browser to take a screenshot, take in and out like raise
assert_selector "h1", text: "13"
end
end
Here is an exmaple of what the test is looking for in the trees_path
:
<% @trees.each do |tree| %>
<h1>tree.age</h1>
<% end %>
Learn more about Minitests here