unit-testing - 如何使用多种方法模拟第三方结构并在依赖于第三方结构的端点上执行单元测试?

标签 unit-testing go getstream-io go-gin

我正在 gin gonic 中使用 getstream 的 Go 库,并意识到我的端点将严重依赖 stream_chat.Client .

例如,在以下端点 (/v1/chat/test-token) 中,必须创建 stream_chat.Client,以便在单元测试中测试此端点意味着创建和维护一个接口(interface),记录我从 stream_chat.Client 使用的所有方法,以便我可以使用满足相同接口(interface)的 MockClient 执行依赖项注入(inject),然后我可以当我编写单元测试时,模拟 chatClient.UpsertUserchatClient.CreateToken 方法。

func main() {
    config.Load()

    server := gin.New()

    chatClient, err := stream_chat.NewClient(config.StreamApiKey, config.StreamApiSecret)
    if err != nil {
        log.Err(err)
        os.Exit(2)
    }

    v1 := server.Group("/v1")
    {
        v1.GET("/chat/test-token/", func(c *gin.Context) {
            _, err := chatClient.UpsertUser(&stream.User{
                ID:   "test-user",
                Role: "admin",
            })

            if err != nil {
                c.JSON(http.StatusInternalServerError, gin.H{})
            }

            token, _ := chatClient.CreateToken("test-user", time.Time{})
            c.JSON(http.StatusOK, gin.H{
                "token": token,
            })
        })
    }
    
    server.Run(fmt.Sprintf(":%s", config.Port))
}

在我看来,记录从 stream_chat.Client 使用的每种方法是相当费力的,以便在端点上保持良好的测试覆盖率,所以我想知道应该做什么在这种情况下?

  1. 维护 stream_chat.Client 的接口(interface)是正确的方法吗?
  2. 不太相关:有没有办法正确地将 gin.HandlerFunc(即 func(c *gin.Context))与 stream_chat 的创建分离。客户端
  3. 甚至不太相关:创建单例 stream_chat.Client 更好,还是应该为每个需要客户端的端点创建一个新客户端?

最佳答案

Is maintaining an interface for stream_chat.Client the correct way to go?

如果您有非接口(interface)依赖项并且您希望使用它对处理程序进行单元测试,那么可以。您需要将 stream_chat.Client 包装在接口(interface)中。

如果第三方结构有很多方法,您可以将接口(interface)拆分为逻辑单元,并仅在每个处理程序中注入(inject)实际需要的方法。底层的 stream_chat.Client 实现了所有这些,但各个模拟可以保持很小并且更容易推理。就我个人而言,我认为不值得为此付出代价。有很多开源模拟生成器,最重要的是 mock and mockgen ,以及从结构生成接口(interface)的工具。

Is there a way to properly decouple the gin.HandlerFunc, i.e. func(c *gin.Context) from the creation of stream_chat.Client?

您有多个选项,可以在这里找到:How to pass arguments to router handlers in Golang using Gin web framework?

简而言之,由于具有更好的单元可测试性,我更喜欢的选项是:

  1. 创建结构体的处理程序方法以及该结构体的依赖项字段。
  2. 使用提供程序模式并将提供程序设置到中间件的 Gin 上下文中

关于unit-testing - 如何使用多种方法模拟第三方结构并在依赖于第三方结构的端点上执行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71426806/

相关文章:

flutter - 如何在 Dart 中模拟 File 实例

go - 将 http.Handler 放入马提尼酒中

inheritance - 转到 : can assign struct to an interface, 但不是上层结构

swift - getStream 中文件模型的访问级别问题

ruby - 单元测试和 SAP 软件

ruby-on-rails - Controller 测试使用 Rspec 显示页面,它给出错误 nil & 并渲染空页面

javascript - 带有只读 token 的 Getstream.io "Not authenticated"

python - GetStream (Django) - 无法丰富通知提要

python - 如何在 django 中构建功能测试、单元测试和其他测试?

rest - 允许使用 3rd 方 API 从我在 Golang 中的 REST 端点下载文件