Tại sao cần sử dụng Factories trong Rails test
Ngày nay, hầu hết các dự án của Rails sử dụng một số form của factories để cài đặt. Vậy những vấn đề nào mà factories có thể giải quyết và tại sao chúng hay đc sử dụng. Có một model User với first_name, last_name, location fields. Chúng ta có thể viết 1 test giống như sau: describe ...
Ngày nay, hầu hết các dự án của Rails sử dụng một số form của factories để cài đặt. Vậy những vấn đề nào mà factories có thể giải quyết và tại sao chúng hay đc sử dụng.
Có một model User với first_name, last_name, location fields. Chúng ta có thể viết 1 test giống như sau:
describe "#full_name" do it "combines first and last name" do user = User.new( first_name: "Joël", last_name: "Quenneville", location: "Boston" ) expect(user.full_name).to eq "Joël Quenneville" end end
Có quá nhiều thông tin được thể hiện trong test case này. field location không liên quan đến ouput của testcase, và khiến chúng ta khó thể chắc chắn được kết quả của test case nếu ko nhìn vào mã nguồn.
it "combines first and last name" do expect(the_test_user.full_name).to eq "Joël Quenneville" end
Nhìn vào đây mình không hiểu được tại sao full_name lại là "Joël Quenneville"? nó đến từ đâu?
it "combines first and last name" do user = User.new(first_name: "Joël", last_name: "Quenneville") expect(user.full_name).to eq "Joël Quenneville" end
Nó chỉ đầy đủ số lượng thông tin.Tất cả các dữ liệu ảnh hưởng đến kết quả là có trong thiết lập. Không có dữ liệu không liên quan nào được đưa vào Hai quy tắc chúng ta cần biết khi viết 1 test case đó là:
- Bao gồm tất cả dữ liệu ảnh hưởng đến kết quả của test case
- Không bao gồm dữ liệu không ảnh hưởng đến kết quả của test case
Giả sử chúng ta ràng buộc các trường bắt buộc không để trống:
class User < ApplicationRecord validates :first_name, presence: true validates :last_name, presence: true validates :location, presence: true end
Nhưng khi viết test thì viết như sau để thỏa mãn quy tắc:
it "downcases the location on save" do user = User.new(location: "Boston") user.save expect(user.location).to eq "boston" end
Nếu như vậy thì test sẽ bị lỗi ngay, chúng ta sẽ chính sửa 1 chút để tránh exception:
it "downcases the location on save" do user = build_user_with_defaults(location: "Boston") user.save expect(user.location).to eq "boston" end def build_user_with_defaults(overrides) defaults = { first_name: "Default", last_name: "Default", location: "Default" } User.new(defaults.merge(overrides)) end
Nhưng chả ai muốn phải viết 1 test case như vậy đúng không ạ? và nó cũng lại thừa các thông tin không cần đến.
Ý tương lấy từ việc xây dựng các giá trị mặc định trước. Sử dụng FactoryBot chúng ta có thể viết:
factory :user do first_name "default" last_name "default" location "default" end
sau đó viết test như sau:
it "downcases the location on save" do user = create(:user, location: "Boston") expect(user.location).to eq "boston" end
Những vấn đề đã được giải quyết và nhìn code của chúng ta khá gọn gàng.
Giống với cách viết test ban đầu, chúng ta hoàn toàn có thể sử dụng factories để tạo ra các đối tượng với những thông tin khác, có thể không liên quan
it "downcases the location on save" do user = create(:user, location: "Boston", first_name: "Joël") expect(user.location).to eq "boston" end
Hoặc nó có thể trả về giá trị mặc định:
it "downcases the location on save" do user = create(:user) expect(user.location).to eq "default" end
Trong nhiều trường hợp, bạn không cần sử dụng factory. Nếu object không có thuộc tính bị ràng buộc hoặc bạn không cần tuân theo Rail’s validations cho test của bạn. Test Factories tồn tại để giải quyết một vấn đề cụ thể. Nếu các test case của bạn không bị ảnh hưởng từ vấn đề đó thì không nên sử dụng factory một cách tùy ý. Ngược lại, nếu bạn sử dụng factory, hãy cẩn trọng khi tạo ra các đối tượng khi thay đổi các thuộc tính tùy ý mà không phục vụ cho kết quả của test case. Trong tất cả trường hợp, luôn luôn nhớ ràng tại sao chúng ta sử dụng factories và những vấn đề nó giải quyết sẽ giúp bạn viết test dễ đọc hơn và nhanh hơn.
Tham khảo: https://robots.thoughtbot.com/why-factories