我正在 gin gonic 中使用 getstream 的 Go 库,并意识到我的端点将严重依赖 stream_chat.Client
.
例如,在以下端点 (/v1/chat/test-token
) 中,必须创建 stream_chat.Client
,以便在单元测试中测试此端点意味着创建和维护一个接口(interface),记录我从 stream_chat.Client
使用的所有方法,以便我可以使用满足相同接口(interface)的 MockClient
执行依赖项注入(inject),然后我可以当我编写单元测试时,模拟 chatClient.UpsertUser
和 chatClient.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
使用的每种方法是相当费力的,以便在端点上保持良好的测试覆盖率,所以我想知道应该做什么在这种情况下?
- 维护
stream_chat.Client
的接口(interface)是正确的方法吗? - 不太相关:有没有办法正确地将
gin.HandlerFunc
(即func(c *gin.Context)
)与stream_chat 的创建分离。客户端
? - 甚至不太相关:创建单例
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?
简而言之,由于具有更好的单元可测试性,我更喜欢的选项是:
- 创建结构体的处理程序方法以及该结构体的依赖项字段。
- 使用提供程序模式并将提供程序设置到中间件的 Gin 上下文中
关于unit-testing - 如何使用多种方法模拟第三方结构并在依赖于第三方结构的端点上执行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71426806/