Test NodeJS application với Jest và SuperTest (still updating)

Trong một ứng dụng NodeJS, việc test các chức năng để đảm bảo kết quả đúng trong dự án là một điều rất quan trọng. Jest được Facebook tạo nên để phục vụ cho mục đích đó. Jest là thư viện của NodeJS cho phép các developer viết test case để test các trường hợp trong ứng dụng một cách dễ dàng, ngoài ra trong trường hợp trước khi deploy lên server cần kiểm tra lại một lượt cũng không cần thiết phải test các chức năng bằng tay, việc này giúp tiết kiệm thời gian, công sức và nâng cao chất lượng sản phẩm.
1. Cài đặt
Để cài đặt Jest, chạy câu lệnh npm install –-save-dev jest
vào project cần test
2. Chạy test đầu tiên trong Jest
Tất cả các file test trong Jest đều phải có đuôi là *.test.js
. Mặc định, Jest sẽ test toàn bộ tất cả các file có đuôi là .test.js
trong tất cả các thư mục. Tuy nhiên nên tạo ra một thư mục tests để chứa tất cả các test case như sau

Thường có 2 loại test cơ bản
- Feature test: Test một request từ đầu đến cuối, bao gồm các service chạy bên trong và các service có liên quan đến nhau. Kết quả test là kết quả sau khi chạy tất cả service
- Units: Test các service hoặc các function độc lập, không liên quan gì đến nhau
Để chạy được bài test đầu tiên, cần viết như sau:

Describe
sẽ tạo ra test title, trong mỗi phần describe sẽ có nhiều hàm test()
con, mỗi test()
là một mục cần test, được đánh dấu bằng dấu (tick) nếu như test thành công, sử dụng dấu (X) nếu test thất bại (Hình 4)
Sử dụng toBe()
để kiểm tra 2 giá trị cần test và nhận được phải giống nhau đúng tuyệt đối
Tạo một script mới để test Jest application

Khi chạy test, kết quả thu được như ở hình dưới. Bật option verbose cho phép nhìn được test đang chạy là test nào và đang test tới đâu và tổng thời gian chạy cho từng test là bao lâu

Trong trường hợp test thất bại, Jest có chỉ ra giá trị thật (received) và giá trị mong muốn (expect) là giá trị nào

Chú ý dùng try catch để bắt lỗi xảy ra trong quá trình viết test case. Chi tiết về try catch sẽ ở phần sau
3. Áp dụng Jest vào dự án
Để áp dụng Jest vào dự án thì cần cài đặt Superagent. Superagent là một thư viện cho phép người dùng tạo ra http request dưới các dạng get, post, put, delete để kiểm tra endpoint của api.
3.1. Cấu hình superagent
Superagent sẽ chạy cùng port với ứng dụng chính. Cài đặt superagent ở đây:

Chi tiết superagent
tại đây: https://www.npmjs.com/package/superagent
Để không phải viết domain và port ở mỗi lần chạy test (như ở dưới, chỉ cần api) thì sử dụng superagent-prefix
. Cài đặt tại đây

Doc cho superagent-prefix tại đây: https://github.com/johntron/superagent-prefix
Trước khi chạy test cần start server node ở môi trường dev. Sau đó chạy test case trên cùng port với môi trường dev.

Chạy test song song với dev server. Khi có thay đổi trong code, cần stop server dev rồi start lại server dev và chạy lại test. (Ví dụ này sau khi đã viết thành công test case)

Để tránh phải viết các hàm superagent.get()
và superagent.post()
, v.v. liên tục có sử dụng accept json hoặc content-type vào tất cả các test thì đinh nghĩa các method chung trong file method, khi cần chỉ việc gọi ra method. Ví dụ khi chạy ở dưới như sau

Khi sử dụng superagent-prefix thì các test sẽ được tự động thêm prefix thông qua method use(prefix)
. Các url để test trong superagent
đều phải có '/' đằng trước
Cuối cùng để jest.setTimeout(30000) để tránh vấn đề jest bị timeout trong quá trình chạy test (có thể do api gọi quá lâu)
3.2. Một số method thông dụng
expect(actual).toBe(expected)
: Kiểm tra xem giá trịactual
có bằngexpected
hay không.expect(actual).toHaveLength(expected)
: Kiểm tra số lượng phần tửactual
có bằng expected hay không (áp dụng cho mảng, chuỗi)expect(actual).toHaveProperty(property, valueExpected?)
: Kiểm traactual
có chứa key property hay không, nếu có thì giá trị có bằng "valueExpected" hay khôngexpect(actual).toBeFalsy()
: Kiểm tra "actual" có false hay không
…
Xem thêm tại: https://jestjs.io/docs/expect
3.3. Xử lí test thành công hoặc thất bại
Trong hầu hết trường hợp thì test sẽ chạy vào điều kiện thành công (tức là trả status là 200, nhưng cũng có trường hợp bắt buộc test phải trả ra lỗi xử lí thế nào)
Tất cả các test đều cần được wrap bằng try-catch, để xử lí trong trường hợp test case thành công và xử lí cả trong trường hợp viết test case bị lỗi thì hiển thị lỗi ra ngoài

Tất cả các test case mà không có status bằng 2xx được tính là lỗi. Khi lỗi xảy ra cần catch error đó và expect toBe()
trong catch như hình ở dưới. Hàm query(params)
cho phép người dùng truyền queryString vào url.

3.4. Các trường hợp test đặc biệt
Một số trường hợp test đặc biệt bao gồm: phải đăng nhập và có access_token
gắn trong header mới tiến hành make request được thì xử lí ra sao
Lúc đó cách tốt nhất là truyền viết 1 hàm tên là authenticated()
và truyền callback vào trong hàm authenticated để set Authorization token cho người dùng

Để set authorization token
cho request thì cần login sử dụng đúng credentials. Sau đó sẽ lấy access token cho người dùng
Để tránh phải login quá nhiều lần khi gọi authenticated()
, cần check userAccessToken trước đó, nếu chưa đăng nhập thì đăng nhập, còn lại thì lưu accessToken vào userAccessToken
Sử dụng authenticated()
bằng cách wrap hàm authenticated()
vào request mình cần gọi. Chi tiết như ở dưới

Có thể mở rộng case này cho các trường hợp khác ví dụ như check quyền người dùng, v.v