【问题标题】:Testing 3rd party package in golang在 golang 中测试 3rd 方包
【发布时间】:2015-03-28 08:42:14
【问题描述】:

我是 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 并远离模拟框架。

谢谢。

【问题讨论】:

    标签: facebook testing go mocking


    【解决方案1】:

    您可以为 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()
    }
    

    【讨论】:

    • 如果我将fbI.Session("asdf") 添加到Facebook 函数中,我会遇到接口转换恐慌。
    • 代码格式不是很好,但在这里。 func main() { Facebook(&MyFbApp{}) } func Facebook(fbI IFbApp) { fbI.ExchangeToken("sometokenhere") fbI.Session("blah") }
    • @lucas 是的,你是对的,这行不通。那么解决方案可能是为 fb.App 实现一个包装器,请参阅更新的答案。
    • 加一。这是façade pattern 的一个示例。
    猜你喜欢
    • 2017-09-29
    • 1970-01-01
    • 2019-05-28
    • 2017-04-10
    • 1970-01-01
    • 2019-03-17
    • 1970-01-01
    • 2020-04-06
    • 1970-01-01
    相关资源
    最近更新 更多