Menguji firmware sebelum merusak hardware: unit testing host-based dengan mock, lapisan SIL dan Hardware-in-the-Loop, static analysis, serta pipeline CI firmware di GitHub Actions yang otomatis membangun, menguji, dan memverifikasi setiap commit.

Setelah di episode 13 firmware kita bisa diperbarui dari jauh, pertanyaan berikutnya adalah: bagaimana memastikan yang kita kirim tidak merusak ribuan perangkat? Jawabannya adalah pengujian sistematis — dan di firmware, pengujian punya tantangan khusus: hardware mahal, lambat, dan tidak selalu tersedia.
Mengapa testing penting? Karena bug firmware sangat mahal: satu bug di lapangan berarti mengganti perangkat, mengirim teknisi, atau memperbarui ribuan unit. 2026 menandai era di mana CI firmware jadi standar rekrutmen (dari episode 1) — perusahaan tidak lagi menerima "saya test manual di board saya". Episode ini membangun fondasi quality engineering yang membedakan produk dari prototype.
Sama seperti software, firmware punya piramida pengujian:
| Lapisan | Lingkungan | Kecepatan | Cakupan |
|---|---|---|---|
| Unit test | Host (PC native) | Milidetik | Logika murni, state machine, parser |
| SIL | Simulasi (QEMU, emulasi) | Detik | Perilaku chip, interrupt, timing |
| HIL | Hardware nyata | Menit | Register nyata, sensor, integrasi |
Aturan praktis: sebanyak mungkin test di unit (cepat, murah), sedikit tapi kritis di HIL (mahal, lambat). Firmware produksi tidak pernah mengandalkan satu lapisan saja.
Kunci unit testing firmware adalah memisahkan logika dari hardware. Kode yang "murni" — state machine, parser, algoritma, kalkulasi sensor — bisa dikompilasi dan diuji di PC:
// parser.c - tanpa hardware sama sekali
int parse_command(const char *buf, uint16_t len, cmd_t *out) {
if (len < 4) return -1;
out->type = (cmd_type_t)buf[0];
out->value = (buf[1] << 8) | buf[2];
return 0;
}Untuk kode yang menyentuh hardware, gunakan mock — ganti fungsi hardware dengan kembalian tetap:
// transport_stub.c (dipakai di test, bukan di firmware)
int i2c_read_regs(...) { return 0; } // mock: selalu sukses
uint8_t mock_buf[4] = {0x10, 0x00, 0x1E, 0x0};Framework populer: Unity + CMock + Ceedling (C), GoogleTest (C++), atau throwaway (test sederhana dengan assert). Test ditulis setara dengan test software biasa.
void test_parse_simple_command(void) {
cmd_t cmd;
TEST_ASSERT_EQUAL(0, parse_command("AB\x01\x00", 4, &cmd));
TEST_ASSERT_EQUAL(CMD_AB, cmd.type);
TEST_ASSERT_EQUAL(0x0100, cmd.value);
}HIL menguji firmware di board nyata dengan kontrol otomatis. Skema khas:
Host (test runner) --USB/serial--> Board
Board --> sensor/aktuator nyata atau simulator
Host baca output, bandingkan dengan ekspektasi, lapor PASS/FAILHIL yang baik menguji: GPIO nyala benar, UART mengirim frame tepat, watchdog berfungsi, dan bootload/OTA benar-benar bisa naik-turun versi. Otomatisasi HIL memakai tool seperti pytest + pyserial, atau framework vendor (STM32CubeMonitor).
CI firmware menjalankan unit test di host (tanpa hardware), membangun binary, dan menyimpan artefak. Contoh workflow GitHub Actions:
name: firmware-ci
on: [push, pull_request]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install toolchain
run: sudo apt-get install -y gcc-arm-none-eabi
- name: Unit tests (host)
run: make test # kompilasi native + jalankan Unity
- name: Build firmware
run: make build # build release binary
- name: Static analysis
run: cppcheck --error-exitcode=1 src/
- name: Check memory usage
run: |
arm-none-eabi-size build/firmware.elf
test $(arm-none-eabi-size -A build/firmware.elf | \
awk '/flash|text/ {sum+=$2} END {print sum}') -lt 60000
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: firmware
path: build/firmware.binPerhatikan langkah terakhir: gate ukuran memori (episode 8) — CI menolak build yang melampaui budget flash/RAM sebelum pernah sampai ke tangan QA.
Tip
Tambahkan formatting check dan linting ke pipeline: clang-format --dry-run untuk gaya konsisten dan cppcheck untuk bug statis. Tim yang men-deploy firmware dengan 100% test hijau tapi penuh inkonsistensi gaya akan kesulitan review — CI yang baik menjaga kualitas, bukan cuma "build sukses".
Susun strategi test produk kalian:
✓ Unit test: state machine, parser, kalkulasi sensor (host, tiap commit)
✓ Build firmware: release + debug (tiap commit)
✓ Memory gate: flash & RAM di bawah budget (tiap commit)
✓ Static analysis: cppcheck / coverity (tiap commit)
✓ HIL: boot, GPIO, UART, watchdog (tiap release / nightly)
✓ OTA test: naik/turun versi + rollback (tiap release)Inti yang harus dibawa pulang:
Di episode 15 selanjutnya kita belajar bahasa yang akan menulis banyak firmware 2026: Rust for Firmware — no_std, embedded Rust, memory safety tanpa garbage collector, dan praktik menulis firmware Rust pertama. Masa depan firmware mulai di sini!