Testing memastikan API kamu bekerja dengan benar dan tidak break saat ada perubahan.
Setup testing dengan Vitest + Supertest:
import { describe, it, expect } from "vitest";
import request from "supertest";
import app from "../src/app.js";
describe("GET /users", () => {
it("should return list of users", async () => {
const res = await request(app).get("/users");
expect(res.status).toBe(200);
expect(res.body).toBeInstanceOf(Array);
expect(res.body.length).toBeGreaterThan(0);
});
});
describe("POST /users", () => {
it("should create a new user", async () => {
const res = await request(app)
.post("/users")
.send({ name: "Budi", email: "[email protected]" });
expect(res.status).toBe(201);
expect(res.body.name).toBe("Budi");
expect(res.body.id).toBeDefined();
});
it("should return 400 without name", async () => {
const res = await request(app)
.post("/users")
.send({ email: "[email protected]" });
expect(res.status).toBe(400);
expect(res.body.error).toBeDefined();
});
});
Pattern: Test happy path + error path:
- Request berhasil → response sesuai
- Input tidak valid → error 400
- Resource tidak ditemukan → error 404
- Tidak terautentikasi → error 401
Mocking Database Calls:
Unit test yang memanggil database sungguhan itu lambat, tidak reliable, dan membuat test saling berinteraksi (test A menghapus data, test B jadi gagal). Solusinya: mock modul database.
// src/db.js
export const db = {
async getUsers() { /* ... query real DB ... */ },
};
// src/userService.js
import { db } from "./db.js";
export const listActiveUsers = async () => {
const users = await db.getUsers();
return users.filter(u => u.active);
};
Cara 1: vi.mock() (Vitest) / jest.mock():
import { describe, it, expect, vi } from "vitest";
import { listActiveUsers } from "../src/userService.js";
import { db } from "../src/db.js";
vi.mock("../src/db.js", () => ({
db: { getUsers: vi.fn() },
}));
it("returns only active users", async () => {
db.getUsers.mockResolvedValue([
{ id: 1, active: true },
{ id: 2, active: false },
]);
const result = await listActiveUsers();
expect(result).toHaveLength(1);
expect(db.getUsers).toHaveBeenCalledOnce();
});
Cara 2: manual stub (dependency injection):
const mockDb = {
query: vi.fn().mockResolvedValue([{ id: 1, name: "Budi" }]),
};
it("returns users from db", async () => {
const result = await listUsers(mockDb); // inject mock
expect(result[0].name).toBe("Budi");
});
Keuntungan mock:
- Cepat — tidak perlu koneksi DB
- Deterministik — test selalu sama hasilnya
- Isolasi — test unit service tanpa bergantung infra
- Test error path — mock bisa throw/reject untuk cek error handling