Interface merupakan suatu tipe data yang berisi kumpulan definisi method (hanya definisi saja) dengan nama tertentu. Untuk default value dari interface adalah nil. Interface syaratnya harus method dan method syaratnya harus ada kepemilikan. Contoh untuk 2 method Greeting code di bawah ini merupakan method milik struct Account dan Customer. Method tersebut dapat ditampung dalam sebuah interface bernama CustomerInterface.
Contoh code 1
package main
import "fmt"
type CustomerInterface interface {
Greeting() string
}
type Account struct {
Name string
Password string
}
type Customer struct {
Name string
AccountID int
}
func (a Account) Greeting() string {
return "Hi " + a.Name
}
func (c Customer) Greeting() string {
return "Welcome " + c.Name
}
// function untuk menggunakan interface dari method beberapa struct.
func NewUser(customerInterface CustomerInterface) string {
return customerInterface.Greeting()
}
func main() {
// variabel yang memiliki method yang sama dengan CustomerInterface
account1 := Account{
Name: "Dana",
Password: "Test123",
}
customer1 := Customer{
Name: "Firman",
AccountID: 1,
}
fmt.Println(NewUser(customer1))
fmt.Println(NewUser(account1))
}
Welcome Firman
Hi Dana
Contoh code 2
package main
import(
"fmt"
)
// type declaration
type Value string
func (v Value) Hello() {
fmt.Println("Hello", v)
}
type Example interface {
Hello()
}
func main() {
var string1 Value = "Andi"
string1.Hello()
var interface1 Example = string1
interface1.Hello()
var string2 Value = "Utsman"
string2.Hello()
var interface2 Example = string2
interface2.Hello()
}
Hello Andi
Hello Andi
Hello Utsman
Hello Utsman
Kegunaan Interface untuk membuat Mocking
Jika suatu fungsi dari suatu package membutuhkan input bertipe interface, kita dapat membuat mockingan dari method yang ada didalam fungsi tersebut.
Semisal ada go module bernama "go-rest-api" yang di dalamnya terdapat 2 file yaitu repository.go dan handler.go.
Di package lain semisal handler.go membutuhkan method CheckUserByName dan Create dari package repository. Package tersebut diinputkan melalui fungsi NewHandler dengan parameter repo bertipe interface.
Semisal ingin membuat unit test dari method Example di package handler yang memanggil method CheckUserByName dan Create. Kita perlu membuat mocking repository yang memiliki method mirip package repository menggunakan package testify/mock seperti dibawah ini.
repositorymock.go
package repositorymock
import (
"github.com/stretchr/testify/mock"
)
type RepoMock struct {
mock.Mock
}
func NewRepoMock() *RepoMock {
return &RepoMock {}
}
func (r *random) CheckUserByName(username string) (isExist bool, err error) {
// sebagai indikator parameter input diperoleh
ret := m.Called(username)
// get return isExist dari mock dengan type assertion
isExist= ret.Get(0).(bool)
if ret.Get(1) != nil {
// get return error dari mock dengan type assertion
err = ret.Get(1).(error)
}
return
}
func (r *random) Create(username string, password string) (err error) {
// sebagai indikator parameter input diperoleh
ret := m.Called(username, password)
if ret.Get(0) != nil {
// get return error dari mock dengan type assertion
err = ret.Get(0).(error)
}
return
}
Mocking-an di atas dapat dijadikan sebagai input di fungsi NewHandler di unit testing seperti code di bawah ini karena fungsi NewHandler menerima input repo dengan tipe interface Repositorier. Interface Repositorier memiliki 2 method yaitu CheckUserByName dan Create. Baik package repository atau repositorymock mempunyai fungsi NewRepository dan NewRepoMock yang mengembalikkan struct yang memiliki 2 method tersebut.
package product
import (
"testing"
"go-rest-api/repositorymock"
"github.com/stretchr/testify/require"
)
func TestExample(t *testing.T) {
// inputkan repoMock ke NewHandler
repoMock := repository.NewRepoMock()
handler := NewHandler(repoMock)
// panggil fungsi Example dari Handler
err := handler.Example("member_01", "Test123")
// jika tidak ada error, maka unit testing PASS
require.NoError(t, err)
}