在golang中测试第三方包。

huangapple go评论80阅读模式
英文:

Testing 3rd party package in golang

问题

我是你的中文翻译助手,以下是你要翻译的内容:

我是golang的新手,尝试使用来自https://github.com/huandu/facebook的facebook包编写一个简单的学习应用程序。

我已经成功获取了该包并连接到了Facebook,并成功调用了Facebook API。这很好,但是我关心的是测试。

起初,我只是调用了方法并在其中创建了一个Facebook对象。然后在进行了一些研究后,我尝试传入我想要模拟的Facebook方法。意识到我需要多个方法,我相信传递接口是正确的方法。

所以我尝试创建了包将实现的接口。

type IFbApp interface {
	ExchangeToken(string) (string, int, error)
	Session(string) IFbSession
}

type MyFbApp struct{}

func (myFbApp *MyFbApp) ExchangeToken(token string) (string, int, error) {
	return myFbApp.ExchangeToken(token)
}

func (myFbApp *MyFbApp) Session(token string) IFbSession {
	return myFbApp.Session(token)
}

type IFbSession interface {
	User() (string, error)
	Get(string, map[string]interface{}) (map[string]interface{}, error)
}

type MyFbSession struct{}
func (myFbSession *MyFbSession) User() (string, error) {
	return myFbSession.User()
}

func (myFbSession *MyFbSession) Get(path string, params map[string]string) (map[string]string, error) {
	return myFbSession.Get(path, params)
}

func SomeMethod() {
    Facebook(fb.New("appId", "appSecret")); // fb calls package
}

func Facebook(fbI IFbApp) {
    fbI.ExchangeToken("sometokenhere");
}

我无法编译此代码,因为出现错误:

cannot use facebook.New("appId", "appSecret") (type *facebook.App) as type IFbApp in argument to Facebook:
	*facebook.App does not implement IFbApp (wrong type for Session method)
		have Session(string) *facebook.Session
		want Session(string) IFbSession

将IFbSession切换为*facebook.Session当然可以编译通过,但是我还需要模拟Session结构体的方法。

我的计划是在我的test.go文件中创建实现我的接口的模拟结构体,并将其传递给要测试的方法。这样做是正确的方法吗?

我希望尽可能地保持纯粹的golang,并尽量避免使用模拟框架。

谢谢。

英文:

I'm new to golang and trying to write a simple learning app using the facebook package from https://github.com/huandu/facebook.

I was able to get the package and connect to facebook and hit the facebook API. This is great but testing is my concern.

At first I was simply calling the method and creating a facebook object inside of it. Then after some research I tried passing in the facebook method I wanted to mock. Realizing there were multiple methods I needed, I am convinced that passing an interface is the right way to go.

So I tried creating interfaces that the package would implement.

type IFbApp interface {
	ExchangeToken(string) (string, int, error)
	Session(string) IFbSession
}

type MyFbApp struct{}

func (myFbApp *MyFbApp) ExchangeToken(token string) (string, int, error) {
	return myFbApp.ExchangeToken(token)
}

func (myFbApp *MyFbApp) Session(token string) IFbSession {
	return myFbApp.Session(token)
}

type IFbSession interface {
	User() (string, error)
	Get(string, map[string]interface{}) (map[string]interface{}, error)
}

type MyFbSession struct{}
func (myFbSession *MyFbSession) User() (string, error) {
	return myFbSession.User()
}

func (myFbSession *MyFbSession) Get(path string, params map[string]string) (map[string]string, error) {
	return myFbSession.Get(path, params)
}

func SomeMethod() {
    Facebook(fb.New("appId", "appSecret")); // fb calls package
}

func Facebook(fbI IFbApp) {
    fbI.ExchangeToken("sometokenhere");
}

I cannot compile this code since I get an error

cannot use facebook.New("appId", "appSecret") (type *facebook.App) as type IFbApp in argument to Facebook:
	*facebook.App does not implement IFbApp (wrong type for Session method)
		have Session(string) *facebook.Session
		want Session(string) IFbSession

Switching IFbSession to *facebook.Session would make it compile of course but then I need to mock methods from the Session struct as well.

My plan was to create mock structs that implement my interfaces in my test.go file and pass it to the methods under test. Is this the right way to go?

I'd like to stay pure golang as much as possible and stay away from mocking frameworks.

Thanks.

答案1

得分: 2

你可以实现一个包装器(wrapper)来覆盖 fb.App 并重写 Session 方法,使其返回 IFbSession 而不是 Facebook.Session

package main

import fb "github.com/huandu/facebook"

type IFbApp interface {
    ExchangeToken(string) (string, int, error)
    Session(string) IFbSession
}

type MockFbApp struct {
    IFbApp
}

func (myFbApp *MockFbApp) ExchangeToken(token string) (string, int, error) {
    return "exchangetoken", 1, nil
}

func (myFbApp *MockFbApp) Session(token string) IFbSession {
    return &MyFbSession{}
}

type IFbSession interface {
    User() (string, error)
    Get(string, fb.Params) (fb.Result, error)
}

type MyFbSession struct {
    IFbSession
}

func (myFbSession *MyFbSession) User() (string, error) {
    return "userid", nil
}

func (myFbSession *MyFbSession) Get(path string, params fb.Params) (fb.Result, error) {
    return fb.Result{}, nil
}

type RealApp struct {
    *fb.App
}

func (myFbApp *RealApp) Session(token string) IFbSession {
    return myFbApp.App.Session(token)
}

func SomeMethod() {
    Facebook(&MockFbApp{})
    Facebook(&RealApp{fb.New("appId", "appSecret")})
}

func Facebook(fbI IFbApp) {
    fbI.ExchangeToken("sometokenhere")
    fbI.Session("session")
}

func main() {
    SomeMethod()
}

希望对你有帮助!

英文:

You can implement a wrapper for fb.App and override Session method to return IFbSession instead of Facebook.Session.

package main
import fb "github.com/huandu/facebook"
type IFbApp interface {
ExchangeToken(string) (string, int, error)
Session(string) IFbSession
}
type MockFbApp struct {
IFbApp
}
func (myFbApp *MockFbApp) ExchangeToken(token string) (string, int, error) {
return "exchangetoken", 1, nil
}
func (myFbApp *MockFbApp) Session(token string) IFbSession {
return &MyFbSession{}
}
type IFbSession interface {
User() (string, error)
Get(string, fb.Params) (fb.Result, error)
}
type MyFbSession struct {
IFbSession
}
func (myFbSession *MyFbSession) User() (string, error) {
return "userid", nil
}
func (myFbSession *MyFbSession) Get(path string, params fb.Params) (fb.Result, error) {
return fb.Result{}, nil
}
type RealApp struct {
*fb.App
}
func (myFbApp *RealApp) Session(token string) IFbSession {
return myFbApp.App.Session(token)
}
func SomeMethod() {
Facebook(&MockFbApp{})
Facebook(&RealApp{fb.New("appId", "appSecret")})
}
func Facebook(fbI IFbApp) {
fbI.ExchangeToken("sometokenhere")
fbI.Session("session")
}
func main() {
SomeMethod()
}

huangapple
  • 本文由 发表于 2015年1月29日 15:43:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/28209358.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定