【问题标题】:How to unit test google cloud storage in golang?如何在 golang 中对谷歌云存储进行单元测试?
【发布时间】:2017-02-10 08:45:59
【问题描述】:

我正在用 Go 编写一个使用 Google cloud storage 的 appengine 应用程序。

例如,我的“阅读”代码如下所示:

client, err := storage.NewClient(ctx)
if err != nil {
    return nil, err
}
defer func() {
    if err := client.Close(); err != nil {
        panic(err)
    }
}()
r, err := client.Bucket(BucketName).Object(id).NewReader(ctx)
if err != nil {
    return nil, err
}
defer r.Close()
return ioutil.ReadAll(r)

...其中ctx 是来自appengine 的上下文。

当我在单元测试中运行这段代码时(使用aetest),它实际上向我的云存储发送请求;我想改为密封运行,类似于 aetest 允许虚假数据存储调用。

(可能与question 相关,但它处理python,并且链接的github issue 表明它以特定于python 的方式解决)。

我该怎么做?

【问题讨论】:

  • @SachinNambiarNalavatttanon 我正在寻找一个假存储;你是在建议我模拟它并自己实现一个假的吗?
  • 如果你最终调用了一个外部资源,你就没有在做单元测试。您有一个功能可以获取文本并查找最常用的单词。此函数获取字节缓冲区并返回结果片段。在测试中,您获取一个字符串并将其转换为字节缓冲区并将其发送到函数,在生产中您从 GCS 读取将文件转换为字节缓冲区并将其发送到函数。

标签: unit-testing google-app-engine go google-cloud-storage


【解决方案1】:

还建议here 的一种方法是允许您的 GCS 客户端在单元测试时将其下载器换成存根。首先,定义一个与您使用 Google Cloud Storage 库的方式相匹配的接口,然后在您的单元测试中使用假数据重新实现它。

类似这样的:

type StorageClient interface {
  Bucket(string) Bucket  // ... and so on, matching the Google library
}

type Storage struct {
  client StorageClient
}

// New creates a new Storage client
// This is the function you use in your app
func New() Storage {
  return NewWithClient(&realGoogleClient{}) // provide real implementation here as argument
}

// NewWithClient creates a new Storage client with a custom implementation
// This is the function you use in your unit tests
func NewWithClient(client StorageClient) {
  return Storage{
    client: client,
  }
}

模拟整个第 3 方 API 可能有很多样板,所以也许您可以通过使用 golang/mockmockery 生成其中一些模拟来简化它。

【讨论】:

    【解决方案2】:

    Python 开发服务器上的云存储是使用带有 Blobstore 服务的本地文件模拟的,这就是使用带有测试平台(也是 Python 特定)的 Blobstore 存根的解决方案有效的原因。但是,Go 运行时上的 Cloud Storage 没有这样的本地模拟。

    正如 Sachin 所建议的,对 Cloud Storage 进行单元测试的方法是使用模拟。这是它在内部和其他运行时(例如node)上完成的方式。

    【讨论】:

      【解决方案3】:

      我做过类似的事情......

      由于存储客户端正在发送 HTTPS 请求,所以我使用 httptest 模拟了 HTTPS 服务器

      func Test_StorageClient(t *testing.T) {
          tests := []struct {
              name        string
              mockHandler func() http.Handler
              wantErr     bool
          }{
              {
                  name: "test1",
                  mockHandler: func() http.Handler {
                      return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                          w.Write([]byte("22\n96\n120\n"))
                          return
                      })
                  },
                  wantErr: false,
              },
              {
                  name: "test2 ",
                  mockHandler: func() http.Handler {
                      return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                          w.WriteHeader(http.StatusNotFound)
                          return
                      })
                  },
                  wantErr: true,
              },
          }
          for _, tt := range tests {
              t.Run(tt.name, func(t *testing.T) {
                  serv := httptest.NewTLSServer(tt.mockHandler())
                  httpclient := http.Client{
                      Transport: &http.Transport{
                          TLSClientConfig: &tls.Config{
                              InsecureSkipVerify: true,
                          },
                      },
                  }
                  client, _ := storage.NewClient(context.Background(), option.WithEndpoint(serv.URL), option.WithoutAuthentication(), option.WithHTTPClient(&httpclient))
                  got, err := readFileFromGCS(client)
                  if (err != nil) != tt.wantErr {
                      t.Errorf("error = %v, wantErr %v", err, tt.wantErr)
                      return
                  }
              })
          }
      }
      

      【讨论】:

        【解决方案4】:

        我建议您尽可能减少模拟,您可能需要使用密封方法使其与真实事物几乎相似。 https://testing.googleblog.com/2012/10/hermetic-servers.html

        【讨论】:

          猜你喜欢
          • 2021-09-26
          • 2022-12-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多