在Golang中模拟外部结构依赖性



我很难弄清楚在Golang中编写可测试代码的习惯方法。我了解接口的重要性及其在测试中的使用,但是我还没有弄清楚如何模拟/测试外部结构依赖项。

作为一个例子,我写了以下内容,以模拟包装器,以在GitHub上创建拉动请求。

type GitHubService interface {
}
type gitHubService struct {
    CreatePullRequest(...) (PullRequest,error)
}
func (s gitHubService) CreatePullRequest(...) (PullRequest,error) {
  tp := github.BasicAuthTransport{
      Username: strings.TrimSpace(/*.....*/),
      Password: strings.TrimSpace(/*.....*/),
    }
    client := github.NewClient(tp.Client())
  pr,err := client.Repositories.CreatePullRequest(...)
  ...
}
func TestPullRequest(t *testing.T) {
  service := gitHubService{}
  pr,err := service.CreatePullRequest(...)
  ...
}

如果我正在为GitHubService.CreatePullRequest(...)编写单元测试,我想模拟对client.Repositories.CreatePullRequest(...)的调用,甚至可能github.NewClient(...)返回我可以控制的模拟实现。

使用诸如gomock之类的工具,您似乎无法使用结构和软件包功能。

处理此问题的惯用方法是什么?我非常适合控制控制和不同模式(例如依赖注入和服务定位器),但我听到无数次这不是惯用的。

GO的一个重要设计功能是 deconpling (观看Bill Kennedy关于该主题的出色演讲)。在您的方法中,有一些依赖性,可以解耦。这种耦合方法使其无法真正测试。

您应该重构的东西:

  • tp := github.BasicAuthTransport:您不应初始化方法内部的授权。它应该作为参数进入您的githubservice。在您的方法调用中,您可以通过s.tp访问IST。您也可以使其成为方法的输入参数。
  • github.NewClient()client.Repositories.CreatePullRequest(...)只需阅读Peter Bourgon的Golang最佳实践,使依赖关系明确!替代方法是创建一个包含所有称为函数的接口。此界面应该是您方法的输入。

脱钩后,您可以非常简单地模拟所有内容。如果将接口用作输入,则可以创建一个模拟结构,该结构实现接口。如果使依赖项明确,则可以覆盖它们。在最后一个情况下,存储呼叫值的代码不是那么干净,但也有效。惯用方法是使用接口。

我也有一个类似的问题,看起来唯一的选择是在其中有另一层将您称为您的"无法锁定"客户端。

例如对于嘲笑GoVMi客户端(vmware客户端的SDK,用于Golang),我必须有一个" mycustomclient"具有接口和结构来拨打govmi.client.client.anymethod ..

我可以为" mycustomclient"生成模拟。

oiggen -source mycustomclient.go -package mypackage -destination mycustomclientmock.go

您可以通过:get get github.com/golang/mock

最新更新