Mocking #
Mocking Test di Golang #
Mocking adalah teknik dalam unit testing di mana objek atau fungsi palsu digunakan untuk menggantikan dependensi yang sebenarnya, memungkinkan pengujian unit secara terisolasi. Dalam konteks Golang, mocking sering digunakan untuk menguji fungsi yang berinteraksi dengan komponen eksternal seperti database, API, atau layanan lainnya.
Mengapa Mocking Penting? #
- Isolasi: Memungkinkan pengujian unit tanpa bergantung pada komponen eksternal.
- Konsistensi: Memungkinkan hasil pengujian yang konsisten tanpa tergantung pada keadaan eksternal.
- Kecepatan: Mengurangi waktu yang diperlukan untuk menjalankan pengujian karena tidak perlu menunggu respons dari layanan eksternal.
Mocking dengan Interface #
Golang menggunakan interface untuk memungkinkan mocking. Dengan mendefinisikan interface untuk dependensi, Anda dapat membuat mock yang mengimplementasikan interface tersebut.
Contoh Penggunaan Mocking #
Berikut adalah contoh aplikasi yang berinteraksi dengan layanan eksternal dan bagaimana melakukan mocking untuk pengujian.
Fungsi yang Akan Diuji #
Misalkan kita memiliki fungsi yang mengambil harga saham dari layanan eksternal.
package main
import (
"fmt"
"net/http"
"io/ioutil"
"encoding/json"
)
// StockService adalah interface yang mendefinisikan metode untuk mengambil harga saham
type StockService interface {
GetPrice(stock string) (float64, error)
}
// RealStockService adalah implementasi dari StockService yang berinteraksi dengan layanan eksternal
type RealStockService struct{}
func (s RealStockService) GetPrice(stock string) (float64, error) {
resp, err := http.Get(fmt.Sprintf("https://api.stockprice.com/%s", stock))
if err != nil {
return 0, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return 0, err
}
var result map[string]float64
if err := json.Unmarshal(body, &result); err != nil {
return 0, err
}
return result["price"], nil
}
// PriceChecker adalah struct yang menggunakan StockService untuk memeriksa harga saham
type PriceChecker struct {
Service StockService
}
func (pc PriceChecker) Check(stock string) (float64, error) {
return pc.Service.GetPrice(stock)
}
Mock untuk Pengujian #
Kita akan membuat mock dari StockService
untuk menguji PriceChecker
tanpa benar-benar memanggil layanan eksternal.
package main
import (
"errors"
"testing"
)
// MockStockService adalah mock dari StockService
type MockStockService struct{}
func (m MockStockService) GetPrice(stock string) (float64, error) {
if stock == "GOOG" {
return 1500.0, nil
}
return 0, errors.New("stock not found")
}
// TestPriceChecker adalah unit test untuk PriceChecker menggunakan MockStockService
func TestPriceChecker(t *testing.T) {
mockService := MockStockService{}
checker := PriceChecker{Service: mockService}
price, err := checker.Check("GOOG")
if err != nil || price != 1500.0 {
t.Errorf("Expected 1500.0, got %f, error: %v", price, err)
}
price, err = checker.Check("AAPL")
if err == nil || price != 0 {
t.Errorf("Expected error, got price: %f", price)
}
}
Penjelasan #
- Definisi Interface:
StockService
adalah interface yang mendefinisikan metodeGetPrice
. - Implementasi Sebenarnya:
RealStockService
adalah implementasi dariStockService
yang memanggil API eksternal untuk mendapatkan harga saham. - Mock Implementasi:
MockStockService
adalah mock dariStockService
yang mengembalikan nilai statis untuk pengujian. - Unit Test:
TestPriceChecker
mengujiPriceChecker
menggunakanMockStockService
untuk memastikan bahwaPriceChecker
berfungsi dengan benar tanpa memanggil layanan eksternal yang sebenarnya.
Alat Bantu Mocking di Golang #
Ada beberapa alat bantu pihak ketiga yang dapat membantu dalam pembuatan mock di Golang, seperti:
- Testify: Paket yang populer untuk assertions dan mock.
- GoMock: Framework untuk membuat mocks dari interface secara otomatis.
Menggunakan Testify #
go get github.com/stretchr/testify
Contoh menggunakan Testify untuk mocking:
package main
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// MockStockService menggunakan Testify untuk mocking
type MockStockService struct {
mock.Mock
}
func (m *MockStockService) GetPrice(stock string) (float64, error) {
args := m.Called(stock)
return args.Get(0).(float64), args.Error(1)
}
// TestPriceCheckerWithTestify menguji PriceChecker menggunakan Testify
func TestPriceCheckerWithTestify(t *testing.T) {
mockService := new(MockStockService)
mockService.On("GetPrice", "GOOG").Return(1500.0, nil)
mockService.On("GetPrice", "AAPL").Return(0.0, errors.New("stock not found"))
checker := PriceChecker{Service: mockService}
price, err := checker.Check("GOOG")
assert.Nil(t, err)
assert.Equal(t, 1500.0, price)
price, err = checker.Check("AAPL")
assert.NotNil(t, err)
assert.Equal(t, 0.0, price)
mockService.AssertExpectations(t)
}
Kesimpulan #
Mocking adalah teknik penting dalam unit testing untuk mengisolasi unit yang diuji dari dependensi eksternal. Di Golang, interface memainkan peran kunci dalam memungkinkan mocking. Dengan menggunakan paket seperti testify
atau gomock
, Anda dapat membuat mock secara lebih mudah dan efisien, memastikan bahwa unit testing Anda kuat dan andal.