12/05/2020 - GO
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.
└── internal
├── app
│ ├── app.go
│ └── app_test.go
└── twitter.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)
}
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,
)
}
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)
}
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
└── internal
├── app
│ ├── app.go
│ └── app_test.go
├── mock
│ └── twitter.go // This is new
└── twitter.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)
}
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,
)
}
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,
)
}
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)
}
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