Herkese merhaba!

Uzun yıllardır bol miktarda kişisel zaman ve enerji harcayarak bilgimizi hepinizle paylaşıyoruz. Ancak şu andan itibaren bu blogu çalışır durumda tutabilmek için yardımınıza ihtiyacımız var. Yapmanız gereken tek şey, sitedeki reklamlardan birine tıklamak olacaktır, aksi takdirde hosting vb. masraflar nedeniyle maalesef yayından kaldırılacaktır. Teşekkürler.

Golang'da birim testleri yazarken servisleri taklit etmek istiyorsanız, sadece arayüzleri kullanabilirsiniz. Testlerinizin "gerçek" kodu çağırmasını istemiyorsanız, genellikle taklit etmek gerekir. Örneğimiz Twitter ile kimlik doğrulaması yapıyor ve ona mesaj gönderiyor.


Yapı


└── internal
├── app
│ ├── app.go
│ └── app_test.go
└── twitter
└── twitter.go

Dosyalar


app.go


package app

import (
"github.com/inanzzz/internal/twitter"
)

type App struct {
client twitter.Twitter
}

func New(c twitter.Twitter) App {
return App{client: c}
}

func (a App) SendMessage(msg string) string {
return a.client.Tweet(msg)
}

twitter.go


package twitter

import (
"fmt"
)

type Twitter struct {
BaseURL string
ClientID string
ClientSecret string
}

func New() Twitter {
return Twitter{
BaseURL: "https://www.real-url.com",
ClientID: "real-id",
ClientSecret: "real-secret",
}
}

func (t Twitter) Tweet(msg string) string {
return fmt.Sprintf(
"Sending '%s' to '%s' using '%s:%s' credentials",
msg,
t.BaseURL,
t.ClientID,
t.ClientSecret,
)
}

app_test.go


package app

import (
"log"
"testing"

"github.com/inanzzz/internal/twitter"
)

func TestApp_SendMessage(t *testing.T) {
twt := twitter.New()

app := New(twt)

res := app.SendMessage("hello")

log.Println(res)
}

Sonuç


Aşağıda görebileceğiniz gibi, testi çalıştırdığımızda, gerçek yapılandırma parametreleriyle gerçek Twitter API'sı çağrıldı. Bu kesinlikle kaçınmak istediğiniz bir şey. Sorunu bir sonraki aşamada çözelim.


=== RUN   TestApp_SendMessage
2020/05/12 17:50:39 Sending 'hello' to 'https://www.real-url.com' using 'real-id:real-secret' credentials
--- PASS: TestApp_SendMessage (0.00s)
PASS

Yapı


└── internal
├── app
│ ├── app.go
│ └── app_test.go
└── twitter
├── mock
│ └── twitter.go // This is new
└── twitter.go

Dosyalar


app.go


Somut olan twitter.Twitter tipi, somut olmayan twitter.SocialMedia arayüzü ile değiştirdik.


package app

import (
"github.com/inanzzz/internal/twitter"
)

type App struct {
client twitter.SocialMedia
}

func New(c twitter.SocialMedia) App {
return App{client: c}
}

func (a App) SendMessage(msg string) string {
return a.client.Tweet(msg)
}

twitter.go


Burada somut olmayan SocialMedia arayüz tanımlandı.


package twitter

import (
"fmt"
)

type SocialMedia interface {
Tweet(msg string) string
}

type Twitter struct {
BaseURL string
ClientID string
ClientSecret string
}

func New() Twitter {
return Twitter{
BaseURL: "https://www.real-url.com",
ClientID: "real-id",
ClientSecret: "real-secret",
}
}

func (t Twitter) Tweet(msg string) string {
return fmt.Sprintf(
"Sending '%s' to '%s' using '%s:%s' credentials",
msg,
t.BaseURL,
t.ClientID,
t.ClientSecret,
)
}

mock/twitter.go


Yarattığımız bu taklit twitter.SocialMedia arayüzünün imzasını tatmin ediyor.


package mock

import (
"fmt"
)

type TwitterMock struct {
BaseURL string
ClientID string
ClientSecret string
}

func (t TwitterMock) Tweet(msg string) string {
return fmt.Sprintf(
"Sending '%s' to '%s' using '%s:%s' credentials",
msg,
t.BaseURL,
t.ClientID,
t.ClientSecret,
)
}

app_test.go


Burada değişken olarak mock.TwitterMock'u enjekte ediyoruz.


package app

import (
"log"
"testing"

"github.com/inanzzz/internal/twitter/mock"
)

func TestApp_SendMessage(t *testing.T) {
twt := mock.TwitterMock{
BaseURL: "https://www.mock-url.com",
ClientID: "mock-id",
ClientSecret: "mock-secret",
}

app := New(twt)

res := app.SendMessage("hello")

log.Println(res)
}

Sonuç


Aşağıda görebileceğiniz gibi, testimiz taklit servisle etkileşime girdi. Mantıklı olduğunda, taklit dosyalardaki değerleri el ile kodlayabilirsiniz.


=== RUN   TestApp_SendMessage
2020/05/12 18:01:51 Sending 'hello' to 'https://www.mock-url.com' using 'mock-id:mock-secret' credentials
--- PASS: TestApp_SendMessage (0.00s)
PASS