Belajar k6 - Modularisasi Skrip & Reusable Function
Series/Belajar k6/Episode 6
Episode 6 of 19

Belajar k6 - Modularisasi Skrip & Reusable Function

Memecah skrip load test menjadi beberapa file dengan ECMAScript modules, membangun fungsi helper untuk HTTP request dan autentikasi, serta merancang fungsi skenario yang bisa dipakai ulang agar test tetap terawat saat tumbuh besar.

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

Pendahuluan

Di episode 5 kalian menguasai teknik yang membuat skrip menjadi hidup: token diekstrak dari respons, sesi disimpan per VU, request paralel lewat http.batch(). Tapi ada efek samping yang tidak bisa dihindari: file skrip semakin panjang. Kode login ditulis ulang di setiap skenario, header Authorization diulang di mana-mana, dan satu perubahan kecil — misalnya URL endpoint berubah — memaksa kalian menyunting banyak tempat.

Episode ini mengajarkan kebiasaan yang membedakan skrip sekali pakai dari aset engineering yang sesungguhnya: modularisasi. Kita akan memecah skrip menjadi beberapa file dengan ECMAScript modules (import/export), membangun reusable function untuk request dan autentikasi, dan merancang skenario yang bisa dipakai ulang lintas test. Analoginya: di episode 5 kalian belajar memasak satu menu; episode 6 mengajarkan menulis buku resep yang bisa dipakai dapur mana pun.

Kenapa Modularisasi

Sebuah load test yang tumbuh tanpa struktur adalah bom waktu. Bayangkan tim kalian punya sepuluh skrip test, masing-masing berisi kode login yang disalin-tempel. Lalu tim auth mengubah format respons login — sekarang sepuluh file harus diperbaiki, dan kemungkinan besar ada yang terlewat. Modularisasi memecahkan tiga masalah sekaligus:

  1. Single source of truth — logika login, helper request, dan konfigurasi hidup di satu tempat. Perubahan cukup di satu file.
  2. Reusability — skrip baru cukup mengimpor fungsi yang sudah ada, bukan menulis ulang.
  3. Readabilitymain.js yang pendek dan jelas jauh lebih mudah di-review daripada satu file 300 baris. Kode yang mudah di-review adalah kode yang bisa di-deploy dengan percaya diri.

Cara Kerja Modul di k6

Sebelum menulis, pahami batasan modul di k6 (ingat pelajaran episode 2: k6 bukan Node.js):

  • Import hanya bisa memakai path relatif ke file skrip, dan wajib menyertakan ekstensiimport { getJson } from "./utils/http-client.js", bukan "./utils/http-client".
  • Kode modul dieksekusi di init context, sekali sebelum VU lahir. Artinya import hanya boleh di level teratas file, dan kode di dalam modul tidak bisa membaca state VU kecuali lewat fungsi yang dipanggil.
  • Modul npm tidak tersedia. Yang bisa diimpor hanya modul bawaan k6/*, modul lokal, dan library dari jslib (kita pakai di episode 8).

Struktur folder yang akan kita bangun:

Struktur folder skrip modular
learn-k6/
├── main.js
├── auth.js
├── config.js
└── utils/
    └── http-client.js

Helper Request: utils/http-client.js

File ini adalah wajah HTTP dari skrip kalian. Alih-alih menulis http.get dengan header Authorization di setiap skenario, kita bungkus dalam fungsi yang bernama jelas:

utils/http-client.js — helper request ber-token
import http from "k6/http";
 
export function getJson(url, token) {
  return http.get(url, {
    headers: {
      Accept: "application/json",
      Authorization: `Bearer ${token}`,
    },
  });
}
 
export function postJson(url, body, token) {
  const headers = { "Content-Type": "application/json" };
  if (token) {
    headers.Authorization = `Bearer ${token}`;
  }
  return http.post(url, JSON.stringify(body), { headers });
}

Kenapa pola ini bernilai? Perhatikan dua hal. Pertama, postJson menangani detail yang mudah terlupa: JSON.stringify untuk body dan header Content-Type. Kedua, token bersifat opsional — request login (belum punya token) dan request terautentikasi bisa memakai fungsi yang sama tanpa duplikasi. Jika suatu hari tim kalian pindah dari header Authorization ke API key, cukup satu file yang berubah, bukan puluhan skenario.

Modul Auth: auth.js

Login adalah logika paling sering diulang dan paling mudah salah. Kita bungkus lengkap dengan pola state per VU dari episode 5, sehingga pemanggil cukup menulis satu baris:

auth.js — login sekali, cache per VU
import http from "k6/http";
 
const sessions = {};
 
export function login(baseUrl, credentials) {
  if (sessions[__VU]) {
    return sessions[__VU];
  }
 
  const res = http.post(`${baseUrl}/login`, JSON.stringify(credentials), {
    headers: { "Content-Type": "application/json" },
  });
 
  const token = res.json("access_token");
  sessions[__VU] = token;
  return token;
}

Perhatikan tiga keputusan desain di balik fungsi ini:

  • Cache per VU: hasil login disimpan di objek sessions yang dikunci __VU — persis pola episode 5, tapi kini dibungkus jadi fungsi. Iterasi kedua hingga seterusnya tidak lagi memanggil /login.
  • Credential sebagai argumen: fungsi ini bisa dipakai ulang dengan akun berbeda (fondasi untuk data-driven testing di episode 8) tanpa mengubah kode login.
  • Mengembalikan nilai, bukan request: pemanggil mendapat token murni, sehingga detail protokol tetap tersembunyi di dalam modul.

Satu catatan: dalam produksi, pertimbangkan token yang kadaluarsa — jika API kalian memakai JWT berumur pendek, tambahkan logika refresh atau hapus cache saat respons 401. Untuk test pendek, pola di atas sudah tepat.

Konfigurasi yang Bisa Di-Export: config.js

Konfigurasi load test juga layak jadi modul sendiri. Dengan fungsi pembangun options, kalian bisa membuat varian test dari satu sumber aturan:

config.js — membangun options secara terprogram
export function buildOptions({ vus, duration }) {
  return {
    vus,
    duration,
    thresholds: {
      http_req_duration: ["p(95)<500"],
      http_req_failed: ["rate<0.01"],
    },
  };
}

Threshold disatukan di satu tempat, sehingga setiap skenario yang memakai buildOptions otomatis mendapat standar kualitas yang sama. Varian beban tinggal disuntikkan lewat argumen — pola ini akan bertemu lagi di episode 7 saat kita menghubungkan konfigurasi dengan environment variables.

Skenario yang Bisa Dipakai Ulang: journeys.js

Satu load test jarang hanya satu request. Pola terbaik adalah menulis perjalanan pengguna (journey) sebagai fungsi yang menerima konteks — di sini baseUrl dan token — lalu memanggil helper:

journeys.js — fungsi skenario yang reusable
import { check, group } from "k6";
import { getJson } from "./utils/http-client.js";
 
export function userJourney(baseUrl, token) {
  group("dashboard", () => {
    const res = getJson(`${baseUrl}/dashboard`, token);
    check(res, { "dashboard 200": (r) => r.status === 200 });
  });
}

Fungsi ini tidak peduli skenario mana yang memakainya. Ia bisa dipanggil dari skrip smoke, skrip load, atau skrip soak — dengan parameter yang berbeda — tanpa ditulis ulang. Inilah inti reusable scenario function: memisahkan apa yang diuji (journey) dari bagaimana bebannya diatur (options dan executor).

Merangkai Semuanya: main.js

Semua modul disatukan dalam satu file utama yang pendek dan ekspresif:

main.js — skrip utama yang tipis
import { sleep } from "k6";
import { getJson } from "./utils/http-client.js";
import { login } from "./auth.js";
import { buildOptions } from "./config.js";
import { userJourney } from "./journeys.js";
 
export const options = buildOptions({ vus: 10, duration: "30s" });
 
const BASE_URL = "https://api.example.com";
const credentials = {
  email: "user@example.com",
  password: "rahasia123",
};
 
export default function () {
  const token = login(BASE_URL, credentials);
 
  userJourney(BASE_URL, token);
 
  sleep(1);
}

Bandingkan dengan satu file 300 baris: main.js ini bisa dipahami dalam tiga puluh detik. Alur eksekusinya jelas — ambil token, jalankan journey, istirahat sebentar. Detail teknis tersembunyi di balik fungsi yang bernama. Itulah tanda arsitektur yang sehat.

Fungsi lifecycle lain juga bisa dimodularisasi: setup dan teardown dapat diimpor dari modul terpisah lalu di-export ulang dari main.js dengan pola export { prepareTestData as setup } — menjaga fase persiapan dan pembersihan tetap terpisah dari beban utama.

Note

Disiplin kunci modularisasi: satu file, satu tanggung jawab. Helper HTTP tidak boleh berisi logika login, auth tidak boleh berisi logika konfigurasi, dan main.js tidak boleh berisi detail request. Jika kalian merasa sebuah file mulai "memikirkan" dua hal sekaligus, saatnya dipecah.

Kesalahan Umum

  1. Melupakan ekstensi .js di import lokal. k6 menolak path tanpa ekstensi dengan error resolusi modul — gejala yang paling sering membingungkan pemula.
  2. Meletakkan logika di level teratas modul. Kode modul dieksekusi di init context sekali saja. Simpan pemanggilan di dalam fungsi, bukan di top-level.
  3. Menyalin helper antar file. Itu melenyapkan alasan modularisasi. Import dari satu sumber.
  4. Membuat fungsi yang terlalu spesifik. loginArifAtStaging() tidak bisa dipakai ulang; login(baseUrl, credentials) bisa.
  5. Menaruh state sesi di luar modul auth. Token yang di-cache di main.js akan kembali bocor antar VU. Kunci __VU harus tinggal di tempat penyimpanannya.

Penutup

Di episode 6 ini kalian telah merapikan skrip k6 menjadi proyek yang terstruktur:

  • ECMAScript modules: import/export antar file, dengan aturan path relatif plus ekstensi .js dan eksekusi di init context.
  • Helper request: getJson dan postJson membungkus detail HTTP dan autentikasi.
  • Modul auth: login() dengan cache per VU, siap dipakai lintas skenario.
  • Konfigurasi terprogram: buildOptions() menyatukan threshold di satu sumber.
  • Reusable journey: fungsi skenario yang menerima parameter, bukan hardcode.

Jalankan hasilnya dengan k6 run main.js dan perhatikan bahwa satu folder kecil ini bisa menghasilkan banyak varian test hanya dengan mengubah argumen. Ada satu tautan yang belum dihubungkan: nilai vus, duration, dan URL masih hardcode. Di episode 7 kita membuka itu — Konfigurasi Load Test dan Environment Variables: merancang stages ramping, menegakkan threshold lanjutan, memakai __ENV untuk parameter runtime, dan menjalankan varian test yang berbeda untuk local, staging, dan lingkungan menyerupai produksi. Sampai jumpa di episode 7!

Belajar k6 - Modularisasi Skrip & Reusable Function | Belajar k6