Cách kiểm tra các API cấp tốc với Jest

Kiểm tra, mặc dù có thể tốn nhiều thời gian, nhưng là một bước quan trọng trong chu trình phát triển của bất kỳ ứng dụng nào. Nó đảm bảo bạn sớm phát hiện ra các lỗi và sự cố trước khi đưa mã vào sản xuất.
Bạn có thể sử dụng Jest để kiểm tra API Express Rest. Sau khi bạn đã tạo một API CRUD đơn giản, hãy khám phá cách viết các bài kiểm tra cho mỗi điểm cuối.
Mục Lục
Jest là gì?
Có nhiều thư viện thử nghiệm JavaScript mà bạn có thể lựa chọn, nhưng Jest là thư viện dễ bắt đầu nhất. Nó là một thư viện thử nghiệm được phát triển bởi Facebook, chủ yếu được sử dụng để thử nghiệm các dự án React. Tuy nhiên, bạn cũng có thể sử dụng nó để kiểm tra Node và các dự án dựa trên JavaScript khác. Nó được phát triển trên Jasmine, một công cụ thử nghiệm khác và đi kèm với thư viện xác nhận của riêng nó.
Mặc dù bạn sẽ không cần thư viện xác nhận để viết các bài kiểm tra trong Jest, nhưng bạn sẽ cần sử dụng một công cụ để thực hiện các yêu cầu HTTP. Bài viết này sử dụng SuperTest.
SuperTest là gì?
SuperTest là một thư viện thử nghiệm Node cho các cuộc gọi HTTP. Nó mở rộng thư viện thử nghiệm siêu cấp và cho phép bạn thực hiện các yêu cầu như GET, POST, PUT và DELETE.
SuperTest cung cấp một đối tượng yêu cầu mà bạn có thể sử dụng để thực hiện các yêu cầu HTTP.
const request = require("supertest")
request("https://icanhazdadjoke.com")
.get('/slack')
.end(function(err, res) {
if (err) throw err;
console.log(res.body.attachments);
});
Tại đây, bạn chuyển URL cơ sở của API đến đối tượng yêu cầu và sau đó chuỗi phương thức HTTP với phần còn lại của URL. Các chấm dứt() phương thức gọi máy chủ API và hàm gọi lại xử lý phản hồi của nó.
Khi bạn nhận được phản hồi từ API, bạn có thể sử dụng Jest để xác thực nó.
Tạo một API Express
Để kiểm tra các điểm cuối API của riêng bạn, trước tiên bạn cần tạo một REST API. API bạn sẽ tạo khá đơn giản. Nó chèn, truy xuất, cập nhật và xóa các mục khỏi một mảng.
Bắt đầu bằng cách tạo một thư mục mới có tên là node-jest và khởi tạo npm.
mkdir node-jest
npm init -y
Tiếp theo, tạo một tệp mới có tên index.js và tạo máy chủ Express.
const express = require("express")
const app = express()
app.listen(3000, () => console.log("Listening at port 3000"))
Kiểm tra Điểm cuối GET / todos
Điểm cuối đầu tiên bạn sẽ tạo là điểm cuối GET / todos. Nó trả về tất cả các mục trong mảng. Trong index.js, hãy thêm phần sau.
const todos = [
];
app.get("/todos", (req, res) => {
return res.status(200).json({
data: todos,
error: null,
});
});
Lưu ý rằng phản hồi có mã trạng thái là 200 và một đối tượng JSON chứa mục việc cần làm trong một mảng được gọi là dữ liệu và một thông báo lỗi. Đây là những gì bạn sẽ kiểm tra bằng cách sử dụng Jest.
Bây giờ, hãy cài đặt Jest và SuperTest:
npm install jest supertest
Sau đó, thêm một tập lệnh thử nghiệm vào package.json như sau:
{
"scripts": {
"test": "jest"
}
}
Trước khi bắt đầu viết bài kiểm tra của riêng mình, bạn nên hiểu cách viết bài kiểm tra cơ bản trong Jest.
Hãy xem xét chức năng sau:
function sum(a, b) {
return a + b;
}
module.exports = sum;
Trong tệp thử nghiệm, bạn cần:
- Nhập hàm.
- Mô tả những gì bài kiểm tra nên làm.
- Gọi hàm.
- Xác nhận phản hồi mong đợi với phản hồi thực tế từ chức năng.
const { sum } = require("./sum")
describe("Sum of two items", async() => {
test("It should return 4", () => {
expect(sum(2,2)).toBe(4)
})
})
Các mô tả từ khóa chỉ định nhóm kiểm tra và kiểm tra tuyên bố chỉ định thử nghiệm cụ thể. Nếu giá trị trả về từ hàm khớp với giá trị được chuyển đến đượcbài kiểm tra vượt qua.
Khi kiểm tra các điểm cuối API, bạn sẽ không gọi một hàm mà gửi một yêu cầu bằng SuperTest hoặc một thư viện máy khách HTTP khác.
Quay lại điểm cuối GET, tạo một tệp mới có tên api.test.js. Đây là nơi bạn sẽ viết tất cả các bài kiểm tra điểm cuối. Đặt tên tệp thử nghiệm bằng .kiểm tra infix đảm bảo rằng Jest nhận ra nó như một tệp thử nghiệm.
Trong api.test.js, nhập supertest và đặt URL cơ sở như sau:
const request = require("supertest")
const baseURL = "http:
Tiếp theo, tạo thử nghiệm đầu tiên trong khối mô tả:
describe("GET /todos", () => {
const newTodo = {
id: crypto.randomUUID(),
item: "Drink water",
completed: false,
}
beforeAll(async () => {
await request(baseURL).post("/todo").send(newTodo);
})
afterAll(async () => {
await request(baseURL).delete(`/todo/${newTodo.id}`)
})
it("should return 200", async () => {
const response = await request(baseURL).get("/todos");
expect(response.statusCode).toBe(200);
expect(response.body.error).toBe(null);
});
it("should return todos", async () => {
const response = await request(baseURL).get("/todos");
expect(response.body.data.length >= 1).toBe(true);
});
});
Trước khi chạy các bài kiểm tra, bạn sẽ cần phải xác định các chức năng thiết lập và xé nhỏ. Các hàm này sẽ điền vào mảng việc cần làm với một mục trước khi kiểm tra và xóa dữ liệu giả sau mỗi lần kiểm tra.
Mã chạy trước tất cả các bài kiểm tra nằm trong hàm beforeAll (). Mã chạy sau tất cả các bài kiểm tra nằm trong hàm afterAll ().
Trong ví dụ này, bạn chỉ cần nhấn vào các điểm cuối ĐĂNG và XÓA cho mỗi điểm cuối. Trong một ứng dụng thực, bạn có thể sẽ kết nối với một cơ sở dữ liệu giả có chứa dữ liệu thử nghiệm.
Trong thử nghiệm này, trước tiên bạn thực hiện một yêu cầu tới điểm cuối GET / todos và so sánh phản hồi được gửi lại với kết quả mong đợi. Bộ kiểm tra này sẽ vượt qua nếu phản hồi có mã trạng thái HTTP là 200, dữ liệu không trống và thông báo lỗi là rỗng.
Kiểm tra điểm cuối POST / todo
Trong index.js, tạo điểm cuối POST / todo:
app.post("/todo", (req, res) => {
try {
const { id, item, completed } = req.body;
const newTodo = {
id,
item,
completed,
};
todos.push(newTodo);
return res.status(201).json({
data: todos,
error: null,
});
} catch (error) {
return res.status(500).json({
data: null,
error: error,
});
}
});
Trong thử nghiệm này, bạn sẽ cần gửi chi tiết việc cần làm trong phần thân yêu cầu bằng phương thức send ().
request(baseURL).post("/todo").send(newTodo)
Yêu cầu POST / việc cần làm phải trả về mã trạng thái 201 và mảng việc cần làm với mục mới được thêm vào cuối. Đây là những gì bài kiểm tra có thể trông như thế này:
describe("POST /todo", () => {
const newTodo = {
}
afterAll(async () => {
await request(baseURL).delete(`/todo/${newTodo.id}`)
})
it("should add an item to todos array", async () => {
const response = await request(baseURL).post("/todo").send(newTodo);
const lastItem = response.body.data[response.body.data.length-1]
expect(response.statusCode).toBe(201);
expect(lastItem.item).toBe(newTodo["item"]);
expect(lastItem.completed).toBe(newTodo["completed"]);
});
});
Ở đây, bạn đang chuyển dữ liệu todo tới phương thức send () như một đối số. Phản hồi phải có mã trạng thái 201 và cũng chứa tất cả các mục việc cần làm trong một đối tượng dữ liệu. Để kiểm tra xem việc cần làm có thực sự được tạo hay không, hãy kiểm tra xem mục nhập cuối cùng trong các việc cần làm được trả lại có khớp với mục nhập bạn đã gửi trong yêu cầu hay không.
Điểm cuối PUT / todos /: id sẽ trả về mục đã cập nhật:
app.put("/todos/:id", (req, res) => {
try {
const id = req.params.id
const todo = todos.find((todo) => todo.id == id);
if(!todo) {
throw new Error("Todo not found")
}
todo.completed = req.body.completed;
return res.status(201).json({
data: todo,
error: null,
});
} catch (error) {
return res.status(500).json({
data: null,
error: error,
});
}
});
Kiểm tra phản hồi như sau:
describe("Update one todo", () => {
const newTodo = {
}
beforeAll(async () => {
await request(baseURL).post("/todo").send(newTodo);
})
afterAll(async () => {
await request(baseURL).delete(`/todo/${newTodo.id}`)
})
it("should update item if it exists", async () => {
const response = await request(baseURL).put(`/todos/${newTodo.id}`).send({
completed: true,
});
expect(response.statusCode).toBe(201);
expect(response.body.data.completed).toBe(true);
});
});
Giá trị đã hoàn thành trong phần nội dung phản hồi phải là true. Hãy nhớ bao gồm id của mặt hàng bạn muốn cập nhật trong URL.
Kiểm tra Điểm cuối DELETE / todos /: id
Trong index.js, tạo điểm cuối DELETE. Nó sẽ trả về dữ liệu việc cần làm mà không có mục đã xóa.
app.delete("/todos/:id", (req, res) => {
try {
const id = req.params.id
const todo = todos[0]
if(todo) {
todos.splice(id, 1)
}
return res.status(200).json({
data: todos,
error: null,
});
} catch (error) {
return res.status(500).json({
data: null,
error: error,
});
}
});
Để kiểm tra điểm cuối, bạn có thể kiểm tra xem mục đã xóa có còn tồn tại trong dữ liệu trả về hay không:
describe("Delete one todo", () => {
const newTodo = {
}
beforeAll(async () => {
await request(baseURL).post("/todo").send(newTodo);
})
it("should delete one item", async () => {
const response = await request(baseURL).delete(`/todos/${newTodo.id}`);
const todos = response.body.data
const exists = todos.find(todo => {
newTodo.id == todoId
})
expect(exists).toBe(undefined)
});
});
Dữ liệu được trả về từ điểm cuối DELETE không được chứa mục đã xóa. Vì các mục trả về nằm trong một mảng, bạn có thể sử dụng Mảng[id] để kiểm tra xem API đã xóa mục đó một cách chính xác hay chưa. Kết quả phải là sai.
Tạo các API REST
Trong bài viết này, bạn đã học cách kiểm tra API Express Rest bằng Jest API. Bạn đã viết các bài kiểm tra cho các yêu cầu HTTP GET, PUT, POST và DELETE và xem cách gửi dữ liệu đến điểm cuối trong URL và yêu cầu. Bạn sẽ có thể áp dụng kiến thức này khi thử nghiệm API Rest của riêng mình.