Thực hành viết rspec trong rails
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 Chạy câu lệnh sau để tạo một application mới có tên là myapp rails ...
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
Chạy câu lệnh sau để tạo một application mới có tên là myapp rails new myapp
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
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 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'
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
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.
Đầ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 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
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