- TDD (Test Driven Development): It is a development technique where the tests are built before starting the real code. In this process, the tests are created based on the requirements, and the code is implemented to pass the tests.
- RSpec: It's a Ruby written language for testing Ruby code. Yeah! This is your testing tool. A language created with Ruby in order to offer an interface to write readable tests for your project. It is an alternative for Minitest, the default Rails testing framework. This is a test example for a User model with RSpec.
RSpec.describe User, type: :model do
it 'name should not have less than 3 characters' do
user = User.new
user.name = 'ab'
user.valid?
expect(user.errors[:name]).to include('is too short (minimum is 3 characters)')
end
end
- Capybara: Another testing tool - a library that enables browser interaction using Ruby. In other words, this one is used to simulate how a user interacts with your web application. It is combined with RSpec to create the 'feature testing' environment. Here is an example of testing with RSpec and Capybara for a 'login' page:
RSpec.feature 'Users', type: :feature do
it 'are redirected to root page when login is sucessfull' do
fill_in 'session_username', with: 'myusername'
fill_in 'session_password', with: 'mypassword'
find("input[type='submit']").click
expect(page).to have_current_path(root_path)
end
end
- DatabaseCleaner: As the name says, it is a tool used to clean the database after tests. It is useful for situations where running a test creates a new object in the database that could interfere with other tests.
- FactoryBot: It allows us to create an object or a collection of objects with predefined sets of values for our tests. What does it mean? If we have a 'User' model, we can create predefined values for different kinds of users. That means it is possible to define a 'random user' and a 'regular user' factory and use them inside your tests, without the need to declare every time. This is a really simple example of how it can be declared used inside our tests:
FactoryBot.define do
factory :user do
name { 'Simple User' }
factory :user_random do
sequence(:name) { |n| "User #{n}" }
end
end
end
RSpec.describe User, type: :model do
it '...' do
user = create(:user) # user.name: 'Simple User'
random_user = create(:user_random) # random_user.name: 'User 1'
random_user = create(:user_random) # random_user.name: 'User 2'
end
end
Setting up the environment
group :test do
# ...
gem 'rspec-rails'
gem 'factory_bot_rails'
gem 'capybara'
gem 'database_cleaner'
end
rails generate rspec:install
RSpec.configure do |config|
# ...
config.include FactoryBot::Syntax::Methods
end
require 'capybara/rails'
First, let's change the config 'config.use_transactional_fixtures = true' to 'false'. It will disable the native rails cleaner.
RSpec.configure do |config|
# ...
config.use_transactional_fixtures = false # CHANGE THIS LINE TO FALSE
# ...
end
RSpec.configure do |config|
# ...
config.before(:suite) { DatabaseCleaner.clean_with(:truncation) }
config.before(:each) { DatabaseCleaner.strategy = :transaction }
config.before(:each, js: true) { DatabaseCleaner.strategy = :truncation }
config.before(:each) { DatabaseCleaner.start }
config.after(:each) { DatabaseCleaner.clean }
end
- Add the gems to Gemfile and 'bundle install';
- Generate RSpec configs: 'rails generate rspec:install';
- Modify 'specs/rails_helper.rb' file to include all gems in RSpec.
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../config/environment', __dir__)
abort('The Rails environment is running in production mode!') if Rails.env.production?
require 'rspec/rails'
require 'capybara/rails'
begin
ActiveRecord::Migration.maintain_test_schema!
rescue ActiveRecord::PendingMigrationError => e
puts e.to_s.strip
exit 1
end
RSpec.configure do |config|
config.before(:suite) { DatabaseCleaner.clean_with(:truncation) }
config.before(:each) { DatabaseCleaner.strategy = :transaction }
config.before(:each, js: true) { DatabaseCleaner.strategy = :truncation }
config.before(:each) { DatabaseCleaner.start }
config.after(:each) { DatabaseCleaner.clean }
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.include FactoryBot::Syntax::Methods
end