Mocking Golang dengan Testify
Beberapa waktu yang lalu, saya mendapatkan tantangan untuk develop aplikasi menggunakan golang. Melihat kultur team yang sudah menerapkan TDD (Test Driven Development) saya juga melihat tantangan golang tidak hanya sintaksis tapi metode-metode yang dapat diaplikasikan dengan kultur pengembangan yang sudah ada.
Pertama kali menggunakan golang, beberapa referensi yang saya baca yakni :
- go by example : https://gobyexample.com/
- golang tour : https://tour.golang.org/
Golang pada dasarnya sudah mempunyai testing library sendiri yang baik yakni testing , namun ada beberapa kondisi yang cukup rumit sehingga membutuhkan bantuan dari library testing lain untuk memenuhi kebutuhan testing kita. Dan salah satu diantaranya adalah Testify (https://github.com/stretchr/testify)
Dengan menggunakan testify beberapa aspek testing disediakan yakni Assert, Required, Mock, Suite.
Kenapa Butuh Mock?
Mock dibutuhkan saat kita ingin memegang kendali testing pada sub function call dalam target testing yang kita lakukan. Sebagai contoh :
func (c *Calculator) Add(a int, b int) int {
filter := Filter{}
checked := filter.Check(a)
if checked {
return a + b
} else {
return 0
}
}fungsi Add(a int, b int) diatas dalam kerjanya melakukan call pada struct function Filter → Check(a). Pada skenario testing, jika kita ingin memegang kendali return value dari fungsi Check() ini, mock dibutuhkan untuk melakukannya.
Untuk menuju testing seperti ini, struktur program disarankan untuk mengikuti https://golang.org/doc/effective_go.html . Walaupun penulis juga masih banyak kurangnya dan sedang berproses menuju effective_go tersebut.
Install Testify
install testify semudah :
go get github.com/stretchr/testifyContoh Kasus
Saya membuat contoh sebuah Calculator sederhana dengan 1 struct function yakni Add(...)
Interface digunakan untuk mendefinisikan perilaku terhadap object yang kita buat. CalculatorInterface mempunyai set function Add(a int, b int) int . Struktur Calculator diset untuk dapat implement FilterInterface. filter akan dipakai saat fungsi Add() berjalan.
Penggunaan c.filter.Check(a) melalui FilterInterface yang dimasukkan kedalam struktur Calculator. memungkinkan filter tersebut dapat dimodifikasi pada level testing.
FilterInterface → Check() dalam contoh ini sederhananya melakukan return true atau false check pada input yang diberikan.
Testing
Saya buat file test calculator_test.go . Pada test ini kita import library go testing dan library testify:
import (
"github.com/stretchr/testify/mock"
"testing"
)Kemudian kita buat Mock Struct dan Function Mock :
type MockFilter struct {
mock.Mock
}
func (m *MockFilter) Check(a int) bool {
args := m.Called(a)
return args.Bool(0)
}MockFilter mengimplement mock.Mock dari testify sehingga MockFilter mempunyai fungsi-fungsi yang sama dengan mock.Mock. Struct Function Check() yang telah di mock mirip seperti prototy untuk melakukan dua hal sederhana, yakni menerima input dan mengembalikan hasilnya. Penggunaan fungsi Check() yang telah di mock dapat dilakukan menggunakan
mock.On().Return()Saat ini kita siap untuk menggunakan mocking pada skenario testing. Skenario testing di golang ditempatkan pada fungsi dengan aturan penamaan
func Test<Object><Function>(t *testing.T) { ... }contoh :
func TestCalcMethod_Add(t *testing.T) { ... }pada function ini kita initnew(MockFilter) ke variable, dalam contoh saya pakai mf. kemudian kita mock call function Check dengan mf.On(“Check”, 5). Return(false)
func TestCalcMethod_Add2(t *testing.T) {
mf := new(MockFilter)
mf.On("Check", 5).Return(false)
...
}setelah itu kita init NewCalculatorWithFilter(mf) ke variable clc. Kemudian kita panggil Add() function melalui variable clc.
func TestCalcMethod_Add2(t *testing.T) {
mf := new(MockFilter)
mf.On("Check", 5).Return(false)
clc := module.NewCalculatorWithFilter(mf)
result := clc.Add(5, 9)
...
}Sampai tahap ini result dari clc.Add(5,9) adalah 0 bukan 14, karena kita mocking Check() yang kita berikan return false dan jika false, fungsi Add() akan mengembalikan nilai 0.
Berikut ini adalah kode testing calculator_test.go selengkapnya.
Tantangan
- Bagaimana cara mock function yang dipanggil oleh function lain dalam satu struct?
