Belajar Solidity - Testing: Foundry & Hardhat
Episode 10 of 23

Belajar Solidity - Testing: Foundry & Hardhat

Menulis pengujian kontrak pintar: test berbasis Solidity dengan forge test dan cheatcode vm.prank, vm.deal, serta vm.warp di Foundry, test berbasis Mocha/Chai + ethers.js di Hardhat, dan pengukuran coverage dengan solidity-coverage

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

Pendahuluan

Setelah di episode 9 kalian mengenal Foundry dan Hardhat sebagai toolchain, pada episode ini kita membahas bagian yang paling menentukan kualitas produksi: testing.

Mengapa testing begitu penting di Solidity? Karena kontrak yang di-deploy adalah immutable — bug yang lolos ke mainnet bisa berarti dana pengguna hilang permanen. Berbeda dengan aplikasi biasa yang bisa di-hotfix, kontrak bermasalah membutuhkan migrasi, proxy, atau kerja keras komunitas. Oleh karena itu, kebiasaan menulis test sebelum release bukan sekadar best practice — ini kebutuhan keselamatan.

Foundry Tests

Test Foundry ditulis dalam Solidity menggunakan library forge-std. Konvensinya: fungsi testXxx dianggap test, dan ada pula pola testFuzzXxx untuk fuzzing.

test/HelloWorld.t.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.36;
 
import {Test} from "forge-std/Test.sol";
import {HelloWorld} from "../src/HelloWorld.sol";
 
contract HelloWorldTest is Test {
    HelloWorld hello;
 
    function setUp() public {
        hello = new HelloWorld("Awal");
    }
 
    function test_InitialGreeting() public view {
        assertEq(hello.greeting(), "Awal");
    }
 
    function test_SetGreeting() public {
        hello.setGreeting("Baru");
        assertEq(hello.greeting(), "Baru");
    }
}
Jalankan test Foundry
forge test -vvv

setUp() dijalankan sebelum setiap test, memastikan isolasi. Output -vvv menampilkan log dan stack trace detail saat test gagal.

Cheatcode: Simulasi Realita

Cheatcode adalah fungsi vm.* yang memanipulasi state EVM untuk simulasi yang sulit dilakukan manual:

CheatcodeFungsiContoh penggunaan
vm.prank(addr)Set msg.sender untuk panggilan berikutnyaMenguji sebagai pemilik
vm.startPrank(addr)Sama, untuk banyak panggilanTransaksi berurutan
vm.deal(addr, amount)Beri ETH ke alamatMenguji fungsi payable
vm.warp(ts)Lompatkan block.timestampMenguji waktu/kadaluarsa
vm.roll(n)Set block.numberMenguji logika blok
solidity
function test_OnlyOwner() public {
    address alice = makeAddr("alice");
    vm.deal(alice, 1 ether);
 
    // Panggil deposit seolah-olah dari alice
    vm.prank(alice);
    vault.deposit{value: 1 ether}();
 
    assertEq(vault.balances(alice), 1 ether);
}
 
function test_Expired_After_Warp() public {
    vm.warp(block.timestamp + 365 days);
    // logika yang bergantung waktu sekarang menganggap sudah lewat
}

Cheatcode inilah yang membuat Foundry sangat produktif: menguji access control, timing, dan pengiriman ETH menjadi sepele.

Hardhat Tests

Test Hardhat ditulis dalam JavaScript/TypeScript dengan Mocha + Chai dan ethers.js:

test/HelloWorld.js
const { expect } = require("chai");
const { ethers } = require("hardhat");
 
describe("HelloWorld", function () {
  it("harus mengembalikan greeting awal", async function () {
    const HelloWorld = await ethers.getContractFactory("HelloWorld");
    const hello = await HelloWorld.deploy("Awal");
    await hello.waitForDeployment();
 
    expect(await hello.greeting()).to.equal("Awal");
  });
});
Jalankan test Hardhat
npx hardhat test

Hardhat menyediakan helper loadFixture untuk mem-deploy sekali per describe block dan snapshot/revert otomatis per test — menjaga suite tetap cepat:

js
const { loadFixture } = require("@nomicfoundation/hardhat-toolbox/network-helpers");
 
async function deployFixture() {
  const hello = await (await ethers.getContractFactory("HelloWorld")).deploy("Awal");
  return { hello };
}
 
it("test 1", async () => { const { hello } = await loadFixture(deployFixture); ... });
it("test 2", async () => { const { hello } = await loadFixture(deployFixture); ... });

Coverage dengan solidity-coverage

Coverage mengukur berapa banyak baris kode yang dieksekusi oleh test:

Coverage di Hardhat
npx hardhat coverage

Di Foundry, kombinasi forge test --gas-report dan forge coverage (via plugin foundry-coverage) memberi gambaran serupa. Coverage yang tinggi bukan jaminan aman, tapi coverage rendah adalah tanda bahaya — target yang sehat adalah di atas 90% untuk fungsi kritis.

Warning

Ingat: coverage hanya mengukur baris yang tereksekusi, bukan kebenaran logika. Uji jalur negatif (fungsi yang harus revert, access control yang ditolak, transfer yang gagal) — bukan hanya jalur bahagia. Ini yang membedakan test yang baik dari test yang sekadar ada.

Ringkasan Workflow Testing

  1. Tulis kontrak dengan logika murni yang mudah diuji.
  2. Buat test untuk setiap fungsi: jalur sukses, jalur revert, access control, dan kasus batas.
  3. Di Foundry gunakan cheatcode vm.prank/vm.deal/vm.warp untuk simulasi.
  4. Di Hardhat gunakan Mocha/Chai + ethers.js dan loadFixture.
  5. Jalankan coverage dan pertahankan angka yang sehat.
  6. Tambahkan fuzzing (kita lanjutkan di episode 18).

Penutup

Inti yang harus dibawa pulang:

  • Test Foundry ditulis dalam Solidity (forge test) dengan cheatcode vm.prank, vm.deal, vm.warp.
  • Test Hardhat ditulis dalam JS/TS (Mocha/Chai + ethers.js) dengan loadFixture.
  • Uji jalur negatif (revert & access control), bukan hanya jalur sukses.
  • Coverage tinggi membantu, tapi logika benar lebih penting.

Di episode 11 selanjutnya kita akan membahas token standards: ERC-20 & ERC-721 — fungsi transfer, approve, transferFrom, konsep decimals, membangun token dengan OpenZeppelin, NFT dengan metadata, royalty ERC-2981, dan multi-token ERC-1155. Sampai jumpa di episode 11!

Belajar Solidity - Testing: Foundry & Hardhat | Belajar Solidity