Belajar Jest - Mocking & Spying
Episode 5 of 23

Belajar Jest - Mocking & Spying

Episode ini membuka mocking engine Jest: membuat fungsi tiruan dengan jest.fn dan jest.spyOn, membedakan manual mocks dan automatic mocks, mengganti modul dengan jest.mock, serta mengendalikan implementasi dan perilaku reset.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Unit test yang baik menguji unit secara terisolasi. Untuk itulah mocking ada: mengganti dependency asli dengan tiruan sehingga test fokus pada perilaku unit itu sendiri, bukan pada perilaku dependency-nya. Episode 5 membuka mocking engine Jest dari empat sisi: mock function, spying, mock modul, dan pengendalian implementasi.

Memahami mocking adalah pembeda antara test yang rapuh dan test yang tangguh. Mock yang salah tempat justru membuat test tidak menguji apa-apa, sedangkan mock yang tepat membuat suite cepat, deterministik, dan bebas dari jaringan eksternal.

Mock Function dengan jest.fn

Membuat dan Mengendalikan Fungsi Tiruan

jest.fn() membuat fungsi tiruan yang bisa dipantau: berapa kali dipanggil, dengan argumen apa, dan apa yang dikembalikan:

JSjest.fn dan pemeriksaan panggilan
test("jest.fn mencatat panggilan", () => {
  const panggil = jest.fn();
  panggil("hello");
  panggil("world");
 
  expect(panggil).toHaveBeenCalledTimes(2);
  expect(panggil).toHaveBeenCalledWith("hello");
  expect(panggil).toHaveBeenLastCalledWith("world");
});

jest.fn() tanpa argumen membuat fungsi yang mengembalikan undefined. expect(panggil).toHaveBeenCalledWith("hello") memeriksa salah satu panggilan sebelumnya, sedangkan toHaveBeenLastCalledWith memeriksa panggilan terakhir.

Menentukan Implementasi

Kalian bisa menetapkan nilai kembali atau implementasi penuh:

JSMenetapkan nilai kembali mock
test("mock dengan nilai kembali", () => {
  const hitung = jest.fn(() => 42);
  expect(hitung()).toBe(42);
 
  hitung.mockReturnValue(7);
  expect(hitung()).toBe(7);
 
  hitung.mockImplementation((x) => x * 2);
  expect(hitung(5)).toBe(10);
});

Ada tiga cara menetapkan perilaku: mockReturnValue untuk nilai tetap, mockResolvedValue untuk promise, dan mockImplementation untuk fungsi penuh. Pilih yang paling sederhana yang memenuhi kebutuhan.

Spying dengan jest.spyOn

Mengamati Objek Tanpa Menghapus Implementasi

jest.spyOn(objek, "metode") mengganti metode sebuah objek dengan tiruan sambil tetap mencatat panggilannya. Berbeda dengan jest.fn, spy default tetap memanggil implementasi asli:

JSjest.spyOn pada objek
const layanan = {
  kirim: (pesan) => `mengirim: ${pesan}`,
};
 
test("spy memanggil implementasi asli", () => {
  const spy = jest.spyOn(layanan, "kirim");
  const hasil = layanan.kirim("halo");
 
  expect(hasil).toBe("mengirim: halo");
  expect(spy).toHaveBeenCalledWith("halo");
  spy.mockRestore();
});

jest.spyOn(layanan, "kirim") mengganti metode sementara; panggilan layanan.kirim("halo") tetap memanggil logika asli karena spy default menembus ke implementasi. spy.mockRestore() mengembalikan metode ke kondisi semula.

Manual Mocks vs Automatic Mocks

Dua Pendekatan Memalsukan Modul

  • Manual mocks: kalian menulis sendiri tiruan sebuah modul di direktori __mocks__, memberi kendali penuh atas bentuk dan perilaku tiruan.
  • Automatic mocks: Jest secara otomatis membuat tiruan berdasarkan struktur modul asli — setiap fungsi diganti jest.fn yang mengembalikan undefined.

Automatic mocks cepat dibuat tetapi sering mengembalikan undefined yang tidak sesuai ekspektasi kode. Manual mocks butuh usaha lebih tetapi jauh lebih realistis. Untuk modul eksternal seperti HTTP client, manual mocks biasanya pilihan yang lebih baik.

Membuat Manual Mock untuk Modul Eksternal

Struktur manual mock
__mocks__/
  http-client.js
src/
  pengguna.js
  pengguna.test.js

Isi __mocks__/http-client.js dengan implementasi tiruan lengkap, lalu panggil jest.mock pada test untuk mengaktifkannya.

Mocking Modul dengan jest.mock

Mengganti Import di Seluruh File

jest.mock("../path/modul") memberi tahu Jest untuk memakai versi tiruan modul tersebut untuk semua import di file test. Jika ada mock manual di __mocks__, itu yang dipakai; jika tidak, Jest membuat automatic mock:

JSjest.mock dengan factory manual
jest.mock("../http-client", () => ({
  get: jest.fn(),
  post: jest.fn(),
}));
 
import { get, post } from "../http-client";
 
test("http-client di-mock", () => {
  get.mockResolvedValue({ data: "ok" });
  return expect(get("/users")).resolves.toEqual({ data: "ok" });
});

jest.mock("../http-client", () => ({ get: jest.fn() })) mengganti seluruh modul dengan factory yang kalian berikan. Keuntungannya: implementasi modul tidak perlu ada — test bisa dijalankan sebelum modul nyata selesai ditulis.

Mengendalikan Reset Behavior

clear, reset, dan restore

Perilaku reset mock sering membingungkan pemula. Ini pembedanya:

  • mockClear(): menghapus catatan panggilan, tetapi mempertahankan implementasi.
  • mockReset(): menghapus catatan dan mengembalikan implementasi ke default kosong.
  • mockRestore(): mengembalikan metode asli untuk spy, sekaligus membersihkan.
JSPembersihan antar test
afterEach(() => {
  jest.clearAllMocks();
});

afterEach(() => { jest.clearAllMocks(); }) membersihkan catatan panggilan semua mock setelah tiap test. Kombinasi ini dengan opsi clearMocks: true di konfigurasi menjaga mock tetap bersih tanpa menyentuh implementasinya.

Penutup

Episode 5 menguasai mocking dan spying: jest.fn() untuk fungsi tiruan yang terpantau, jest.spyOn() untuk mengamati objek tanpa menghapus implementasi, jest.mock() untuk mengganti modul, serta pemahaman manual mocks versus automatic mocks dan strategi reset yang tepat.

Inti yang harus dibawa pulang:

  • jest.fn() untuk mock function; jest.spyOn() untuk objek yang masih dipanggil aslinya.
  • mockReturnValue, mockResolvedValue, dan mockImplementation untuk perilaku mock.
  • Manual mocks memberi kendali penuh; automatic mocks cepat tetapi sering terlalu kosong.
  • jest.mock() mengganti modul di seluruh file test.
  • mockClear, mockReset, dan mockRestore punya peran berbeda — pahami masing-masing.
  • afterEach dengan jest.clearAllMocks menjaga mock tetap bersih antar test.

Di episode 6 selanjutnya kita akan menangani asynchronous testing — menguji promise dengan resolves dan rejects, pola async/await, callback dengan done, serta pengendalian timer dengan fake timers. Ini wajib dikuasai karena sebagian besar aplikasi modern penuh dengan operasi async.