Học lập trình Ruby on Rails
Thực hành Test Driven Development (TDD) trong Ruby on Rails

Thuật ngữ TDD đã không còn xa lạ với các lập trình viên Việt Nam. Trong bài này Tác giả xin chia sẻ một phần của buổi học về TDD trên lớp Ruby on Rails tại Techmaster.

1.  Khái Niệm

TDD là viết tắt của Test Driven Development, cái này chắc ai cũng biết rõ.

TDD còn được hiểu là quá trình Red - Green - Refactoring liên tục trong quá trình phát triển phần mềm

Cụ thể hơn thì TDD có nghĩa là:  

  • Viết Tests trước - sau đó chạy bộ tests vừa viết --> Đỏ lòm vì viết Test trước, chưa có code.
  • Code chạy được --> chạy lại bộ Tests --> Pass hết và màu xanh hết.
  • Refactor code cho ngon --> Chạy lại bộ Tests --> Vẫn phải xanh hết.

Điều đó có nghĩa, bạn dành thời gian viết Test, và viết càng cẩn thận, thì về sau bạn Refactor code của mình càng dễ dàng và mạnh dạn :) --> nâng cao chất lượng sản phẩm.

Bạn viết Test tốt --> Về sau nâng cấp hoặc thay đổi chức năng --> bạn vẫn mạnh dạn sửa mà không sợ làm ảnh hưởng các bên liên quan.

  • Test --> Hiểu được requirement rõ ràng hơn.
  • Test --> giảm thiểu được bugs
  • Test --> giảm công sức cho QA, giảm thiểu thời gian test lại sau mỗi lần nâng cấp sản phẩm.

2. Thực Hành với Ruby on Rails

Note: Các bạn nếu chưa từng làm quen với Ruby on Rails nhưng muốn thực hành có thể tham khảo 2 bài đọc khác của Tác giả tại Techmaster.
https://techmaster.vn/posts/12510/nhap-mon-ruby

https://techmaster.vn/posts/7125/ruby-on-rails-mo-dau

  • Test Model

Ở bài viết này, tác giả sẽ giới thiệu cách viết Tests sample sử dụng RSpec cho một model rất cơ bản: User với thuộc tính rất cơ bản như user_id, name, smartphone_os. Trong đó user_id String, không bị trùng lặp, ví dụ 'U001', 'U002', smartphone là thuộc tính hệ điều hành mà điện thoại người đó sử dụng, chỉ có thể là 'IOS' hoặc 'Android', còn name là tên của user, độ dài từ 4 - 30 kí tự, chỉ gồm chữ cái. Tất cả các thuộc tính đều là bắt buộc khác null.

Thêm thư viện rspec-rails

#Gemfile

# ...
group :development, :test do
  #...
  gem 'rspec-rails', '~> 3.0'
end

Các bạn cần chạy lại  bundle install và cấu hình rspec

bundle install & rails generate rspec:install

Sinh tự động model User và file test model user_spec.rb

rails generate model User name:string user_id:string smartphone_os:string

Create và Migrate database 

rake db:create db:migrate

Ok, giờ chúng ta đã có thể viết Test cho model User vừa tạo

Các bạn mở file spec/models/user_spec.rb

require 'rails_helper'

RSpec.describe User, type: :model do
  ## create user and assign to user variable
  let(:user) { User.create(user_id: 'U1001', smartphone_os: 'IOS', name: 'Techmaster') }

  describe "invalid" do
    describe "user_id" do
      it "not presence" do
        user.userID = ""
        expect(user).not_to be_valid
      end
      
      it "duplicate" do 
        duplicate_user = User.new(user_id: 'U1001' smartphone_os: 'Android', name: 'Techmaster 01'
        expect(duplicate_user).not_to be_valid
      end
    end

    describe "smartphone_os" do
      it "not presence" do
      end

      it "not in list" do
      end    
    end

    describe "name" do
      it "not presence" do
      end

      it "too long" do
      end

      it "too short" do
      end

      it "includes number" do
      end
    end
end

Trong file spec ở trên, Tác giả đã liệt kê ra những trường hợp mà user không được phạm dựa theo requirement của bài toán. 

Ngoài type: :model, Rspec còn cung cấp thêm một số type khác như :controller:request, :view, :routing, :helper.

Phần 1 này chúng ta sẽ chỉ làm quen với :model

Đầu tiên chúng ta tạo đối tượng user cho các test case ở phía dưới

  ## create user and assign to user variable
  let(:user) { User.create(user_id: 'U1001', smartphone_os: 'IOS', name: 'Techmaster') }

Ở đây chúng ta sử dụng cú pháp let của RSpec và cú pháp tạo đối tượng như trong rails console của Ruby on Rails

Một điều mà mình muốn chú ý đó là các viết describe và it. Hơi khó diễn tả nhưng các bạn có đọc sample có thể thấy mình nên chia cụ thể, rõ ràng, và mô tả đúng, vừa đủ điều các bạn test. Mỗi describe sẽ tương ứng với một bộ user use cases và mỗi it sẽ tương ứng với một test case.

Còn về cú pháp "expect(sth).to ... " của RSpec, các bạn có thể tham khảo thêm tại RSpec expectations

Nếu các bạn muốn test user valid, các bạn có thể tham khảo code ở dưới

require 'rails_helper'

RSpec.describe User, type: :model do
  ## create user and assign to user variable
  let(:user) { User.create(user_id: 'U1001', smartphone_os: 'IOS', name: 'Techmaster') }
  
  subject { user }

  ## user should be valid
  it { should be_valid }

  ## ...
end

Well done, keep going on my next articles :)