Skip to content

Instantly share code, notes, and snippets.

@ynwd
Last active November 26, 2020 08:30
Show Gist options
  • Save ynwd/89b5bc287a423673712bfa8366541500 to your computer and use it in GitHub Desktop.
Save ynwd/89b5bc287a423673712bfa8366541500 to your computer and use it in GitHub Desktop.
Super Easy Golang Test and Mock Explanation

Test dan Mock Menggunakan Testify

Catatan ini merupakan sambungan dari Kegunaan Interface. Kode-kode yang digunakan di page ini terkait dengan page tersebut.

Coba perhatikan kode berikut:

package main

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestGreet(t *testing.T) {
	repo := NewRepository()
	service := NewGreeter(repo, "en")
	msg := service.Greet()
	assert.Equal(t, "bzzzz", msg)
}

Simpan kode di atas menjadi file main_test.go.

Kode diatas bertujuan untuk membandingkan string "bzzzz" dengan nilai dari method Greet().

Jalankan test:

go test

Hasilnya:

PASS
ok      mock    0.003s

Testing Menggunakan Mock

Sebenarnya tidak ada masalah testing menggunakan cara di atas. Hasilnya sudah PASS.

Hanya saja, jika kasusnya kompleks, maka perlu usaha lagi.

Misalnya saja:

  • Apa yang terjadi jika repo di atas ternyata harus terkoneksi ke database?
  • Sementara itu, kita tidak bisa mengakses database tersebut. Karena tidak punya password dan username-nya, misalnya.
  • Padahal, yang kita inginkan sebenarnya hanya ingin mengetahui, fungsi Greet() ini sudah sesuai dengan ekspektasi apa belum.

Di sinilah kegunaan mock: mengganti nilai yang dibutuhkan Greet() dengan cara mengontrol implementasi method yang ada di Repository.

Perhatikan kode berikut:

package main

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

// Inisialisasi Mock
type repoMock struct {
	mock.Mock
}

func (d *repoMock) FetchMessage(lang string) (string, error) {

	args := d.Called(lang)

	return args.String(0), args.Error(1)
}

// Penggunaan mock
func TestMockMethodWithArgs(t *testing.T) {

	theRepoMock := repoMock{}

	// if FetchMessage("id") is called, then return "lah"
	theRepoMock.On("FetchMessage", "id").Return("lah", nil)

	g := greeter{&theRepoMock, "id"}

	assert.Equal(t, "lah", g.Greet())

	theRepoMock.AssertExpectations(t)
}

Inisialisasi Mock

  • Perhatikan bahwa struct repoMock mempunyai signature yang sama dengan interface Repository. Cek kode berikut.
  • parameter lang, di-inject dengan method d.Called(lang)
  • method FetchMessage mengembalikan nilai yang di-inisialisasi oleh return args.String(0), args.Error(1).
    Perhatikan: signature type-nya harus sama.

Penggunaan mock

  • Method theRepoMock.On("FetchMessage", "id").Return("lah", nil) dibuat untuk mengontrol dan mengubah perilaku method FetchMessage.
  • Method tersebut mengganti balikan FetchMessage yg defaultnya string "bzzzz" dengan string "lah".
  • Instance theRepoMock kemudian di-inject ke greeter struct.
  • Perlu diingat, bahwa greeter struct itu sudah memiliki field Repo yang type-nya Repository.
  • Karena type-nya sudah sama, maka perilaku FetchMessage sudah diganti dengan definsi baru.

Testing

Jalankan perintah ini:

go test -v

Hasilnya:

=== RUN   TestMockMethodWithArgs
    main_test.go:39: PASS:      FetchMessage(string)
--- PASS: TestMockMethodWithArgs (0.00s)
PASS
ok      mock    0.003s

Kode sumber catatan ini bisa diakses di tautan berikut

What's next

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment