Thực hành viết rspec trong rails
Bài đăng này đã không được cập nhật trong 8 năm
Bài viết này nhằm giới thiệu tổng quan và cách cài đặt rspec trong rails. Những nội dung chính trong bài:
- Setup rspec
- Tạo factory dử dụng Factory Girl Rails và Faker
- Viết Model specs
- Viêt Controller specs
- Feature specs
Tạo một rails application
Chạy câu lệnh sau để tạo một application mới có tên là myapp
rails new myapp
Cài đặt RSpec
Trong Gemfile thêm vào gem "rspec-rails"
vào nhóm development, test
group :development, :test do
gem "byebug", platform: :mri
gem "rspec-rails", "~> 3.4"
end
Chạy lệnh bundle
để cài đặt RSpec,
tiếp theo bạn chạy câu lệnh
rails generate rspec:install
với câu lệnh này sẽ tự động thêm thư mục spec và một vài file với duôi lài .rspec
Shoulda-Matchers và Database Cleaner
Mở file Gemfile và thêm vào test group hai gemshoulda-matcher
và database_cleaner
group :test do
gem 'shoulda-matchers', '~> 3.0', require: false
gem 'database_cleaner', '~> 1.5'
end
chạy lệnh bundle
Cấu hình Shoulda-Matchers
Shoulda-Matcher cung cấp match one-line tới RSpec để sử dụng trong test các chức này năng của Rails mà chúng ta sẽ thấy ngay đây thôi. Mở spec/rails_helper.rb và thêm đoạn code sau
require 'shoulda/matchers'
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end
Cấu hình Database Cleaner
Database Cleaner cung cấp cách để dọn dẹp cơ sở dữ liệu của bạn trong Ruby giữa chạy thử nghiệm. Nó đảm bảo làm sạch trạng thái cho testing.
để tích hợp database_cleaner chỉ cần chỉnh lại trong file rails_helper
config.use_transactional_fixtures = false
Tạo một thư mục mới gọi là support trong thư mục spec. Trong thư mục này tạo một file có tên là database_cleaner.rb và paste đoạn code sau vào
RSpec.configure do |config|
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
Vậy là database_cleaner đã được thiết lập. Và từ đây nó sẽ dọn dẹp database mỗi làn chạy unitest
Capybara Setup
Capybara là một framework tự động sử dụng để tạo chức năng test mô phỏng lại các users sử dụng và tương tác với ứng dụng như thế nào. Thêm gem capybara vào test group development, :test
trong Gemfile và chay bundle
Mở spec_helper.rb và thêm require sau
require 'capybara/rspec'
Cài đặt Faker và Factory Girl
Faker được dùng để tạo dữ liệu random cho việc test của chúng ta. bạn sẽ nhìn thấy nó với factory_girl_rails. thêm gem faker trong :test
trong test group
gem "faker"
Tiếp đén Factory Girl cho phép bạn tạp object cần thiết khi test. kết hợp với faker bạn có thể tạo random một object có random dữ liệu khi test thay vì chỉ có một giá trị default.
Tạo một Factory
Tạo một thư mục tên là spec factories trong folder spec. tiếp theo thêm file sau model của bạn. Ví dụ contacts.rb
FactoryGirl.define do
factory :contact do
full_name { Faker::Name.name }
email { Faker::Internet.email }
phone_number { Faker::PhoneNumber.phone_number }
address { Faker::Address.street_address }
end
end
Trong đoạn code trên bạn có thể thấy cách mà tạo ra một dữ liệu cố định sử dụng factory_girl_rails và faker
Model Specs
Muốn hắc chắn dữ liệu trong factory mà tạo ở trên là một valid modlel, tạo một file trong modle/spec:
require 'rails_helper'
RSpec.describe Contact, type: :model do
it "has a valid factory" do
expect(contact).to be_valid
end
end
chạy lệnh rspec spec/modle/contact_spec.rb
nó sẽ thông báo có một lỗi xảy ra vì không có model contact. Giờ chúng ta sẽ tạo một model Contact với các thuộc tính cơ bản bằng câu lệnh sau trong terminal
rails g model Contact full_name:string email:string phone_number:integer address:text rake db:migrate
Chúng ta sẽ sử dụng shoulda-natchers bao bên ngoài model test để validate presence của full_name, phone_number và address.
describe Contact do
it { is_expected.to validate_presence_of(:full_name) }
it { is_expected.to validate_presence_of(:email) }
it { is_expected.to validate_presence_of(:phone_number) }
it { is_expected.to validate_presence_of(:address) }
end
chạy lại câu lệnh rspec trên bạn sẽ thấy nó fail. Để nó pass qua hết chỉ cần thêm validates_presence_of :full_name, :email, :phone_number, :address
và trong contact.rb
và chạy lại lần nữa, nó sẽ pass qua hết.
Controller Spec
Đầu tiên controller spec sẽ kiểm tra một new contact được created với các thuộc tính có giá trị hợp lệ. Trong terminal gõ lệnh sau để tạo controller cho contact
rails g controller Contacts
với câu lệnh này cũng tự động sinh ra nhưng folder cần thiết cho controller spec. Lần này để viết spec test create action trong file spec/controllers/contacts_controller_spec.rb
require 'rails_helper'
RSpec.describe ContactsController, type: :controller do
describe "POST #create" do
context "with valid attributes" do
it "create new contact" do
post :create, contact: attributes_for(:contact)
expect(Contact.count).to eq(1)
end
end
end
end
Tương tự như viết spec modlel chạy câu lệnh rspec spec/controllers/contacts_controller_spec.rb
sẽ fail vì không có route thích hợp với controller. Vì thế bạn cần thêm resources :contacts
vào file routes.rb
chạy lại câu lệnh trên một lần nữa nhưng vẫn sẽ fail với error The action 'create' could not be found for ContactsController.
do vậy phải thêm đoạn code sau vào contacts_contact.rb
def new
_@contact = Contact.new
end
def create
_@contact = Contact.new contact_params
if _@contact.save
redirect_to @contact
else
render :new
end
end
end
private
def contact_params
params.require(:contact).permit :full_name, :email, :phone_number, :address
end
lần này bạn chạy lại lệnh rpec và nó sẽ pass
Feature Spec
Feature Spec là test ở mức cao. làm việc trên application và chắc chắn rằng các thành phần của app đều hoạt động. kiểu test này sẽ đứng ở góc đọ user
để có cái nhìn tổng quát bạn sẽ viết một spec để kiểm tra việc tạo ra một new contact. Sử dụng gem Capybara, spec sẽ điền vào form các giá trị hợp lệ và show pasge sẽ hiển thị ra những gì chúng ta mong đợi sau khi tạo contact xong.
Tạo folder và file sau spec/features/contacts/create_spec.rb và thêm đoạn code sau vào:
require 'rails_helper'
RSpec.feature "Contact", :type => :feature do
scenario "Create a new contact" do
visit "/contacts/new"
fill_in "Full name", :with => "My Name"
fill_in "Email", :with => "my@email.com"
fill_in "Phone number", :with => "123456789"
fill_in "Address", :with => "34, Allen Way, OA"
click_button "Create Contact"
expect(page).to have_text("My Name")
end
end
Các spec test trên nếu show page có chữ My Name
, đó là giá trị được fill vào full_name
. Chạy spec này và nó sẽ fail.
Đầu tiên phải thêm một show action vào controller:
def show
_@contact = Contact.find params[:id]
end
Tiếp theo lần lượt tạo các file sau new.html.erb, _form.html.erb, show.html.erb và fill đoạn code tương ứng
***app/views/contacts/_form.html.erb***
<%= form_for(@contact) do |f| %>
<% if @contact.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@contact.errors.count, "error") %> prohibited this contact from being saved:</h2>
<ul>
<% @contact.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :full_name %><br>
<%= f.text_field :full_name %>
</div>
<div class="field">
<%= f.label :email %><br>
<%= f.text_area :email %>
</div>
<div class="field">
<%= f.label :phone_number %><br>
<%= f.text_area :phone_number %>
</div>
<div class="field">
<%= f.label :address %><br>
<%= f.text_area :address %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
***app/views/contacts/new.html.erb***
<h2>Create new contact</h2>
<%= render 'form' %>
***app/views/contacts/show.html.erb***
<p id="notice"><%= notice %></p>
<p>
<strong>Full Name:</strong>
<%= @contact.full_name %>
</p>
<p>
<strong>Email:</strong>
<%= @contact.email %>
</p>
<p>
<strong>Phone Number:</strong>
<%= @contact.phone_number %>
</p>
<p>
<strong>Address:</strong>
<%= @contact.address %>
</p>
chạy rspec và nó sẽ pass
Kết luận
Bài viết này mang tính chất giới thiệu về RSpec, cách cài đặt cũng như một số cách sử dụng cơ bản. Đây chỉ là những bước cơ bản đầu tiên, Và từ đây bạn có thể khám phá nhiều giá trị và lợi ích của rspec
All rights reserved