Apa itu Unit Testing?

Testing bagian kecil dari program secara terpisah.

Tujuannya:

Memastikan function atau logic bekerja sesuai yang diharapkan.


Basic Test

File test harus:

*_test.go

Contoh:

func Add(a, b int) int {
	return a + b
}

Test:

func TestAdd(t *testing.T) {
	result := Add(2, 3)

	if result != 5 {
		t.Errorf("expected 5, got %d", result)
	}
}

Jalankan:

go test

t.Errorf() vs t.Fatal()

t.Errorf()

Melaporkan error, tapi test masih lanjut.

t.Errorf("expected 5, got %d", result)

t.Fatal()

Melaporkan error dan langsung menghentikan test.

t.Fatal("result is nil")

Singkatnya:

Error → lanjut
Fatal → berhenti

Pola Test

Ingat:

Arrange → Act → Assert
// Arrange
a := 2
b := 3

// Act
result := Add(a, b)

// Assert
if result != 5 {
	t.Errorf("expected 5, got %d", result)
}

Test Error

Kalau function mengembalikan error:

err := ValidateTitle("")

Untuk memastikan error terjadi:

if err == nil {
	t.Fatal("expected error")
}

Untuk memastikan tidak ada error:

if err != nil {
	t.Errorf("unexpected error: %v", err)
}

Testing Service

Misalnya:

Handler
   ↓
Service
   ↓
Repository

Saat mengetes Service, kita biasanya tidak perlu menggunakan database asli.

Gunakan:

Service
   ↓
Fake / Mock Repository

Tujuannya supaya test fokus ke logic service.


Kenapa Interface Berguna?

Contoh:

type Repository interface {
	Create(title string) error
}

Service:

type service struct {
	repo Repository
}

Karena menggunakan interface, repository bisa diganti dengan fake saat testing.

Real Repository → Database

Fake Repository → Unit Test

Command Penting

Test package saat ini:

go test

Test semua package:

go test ./...

Test dengan detail:

go test -v

Test function tertentu:

go test -run TestAdd

Coverage:

go test -cover

Yang Perlu Diingat

Unit Test
    ↓
Test bagian kecil
    ↓
Function / Method
    ↓
Input → Function → Output
    ↓
Bandingkan dengan expected result

Tujuan utama:

Bukan membuat banyak test, tapi memastikan behavior penting dari program tetap benar.

Test juga berguna saat refactoring, karena membantu memastikan perubahan kode tidak merusak behavior yang sudah ada.