在golang中进行集成测试时如何模拟外部http请求api

Posted

技术标签:

【中文标题】在golang中进行集成测试时如何模拟外部http请求api【英文标题】:How to mock external http request api when integration test in golang 【发布时间】:2022-01-24 04:42:16 【问题描述】:

我有一项服务可以获取数据库数据并从第三方 api 获取其他数据。

像这样:

type Service interface 
     GetDataFromDB(params apiParams, thirdClient ApiCient)


type Repository interface 
     GetDataFromDB(orm *gorm.DB)

 
type DataService struct 
     repo Repository


func (s *DataService) GetDataFromDB(params apiParams, thirdClient ApiClient) []interface 
     var result []interface
     dataFromDb := s.repo.GetDataFromDB()
     dataFromAPI := thirdClient.Do(url)
     result = append(result, dataFromDb)
     result = append(result, dataFromAPI)
     return result
 



func getData(c *gin.Context) 
     //already implement interface 
     repo := NewRepository(orm)
     srv := NewService(repo)
     thirdPartyClient := NewApiClient()
     params := &paramsId:1,Name:"hello world"
     res := srv.GetDataFromDB(params, thirdPartyClient)
     c.JSON(200,res)


func TestGetData(t *testing.T) 
     w := httptest.NewRecorder()
     request := http.NewRequest(http.MethodGet, "/v1/get_data", nil)
     route.ServeHTTP(w, request)

第三方api客户端会返回随机数据。 在这种情况下,我该怎么办? 如果我想模拟客户端以获得稳定的数据进行测试,如何在集成测试中伪造它?

【问题讨论】:

This article 有一些好的建议。 【参考方案1】:

我假设“集成测试”意味着您将运行整个应用程序,然后测试正在运行的实例及其依赖项(在您的情况下是数据库和第三方服务)。我假设您不是指单元测试。

对于集成测试,您有几个选择。就我而言,通常我会进行集成测试,包括第三方客户端连接的任何内容(没有模拟),因为我想测试我的服务与第三方服务的集成。或者,如果这不可能,我可能会编写一个与第三方服务具有相同公共接口的简单存根应用程序,并在本地主机(或其他地方)上运行它,以便我的应用程序在测试期间连接到。

如果你不想或不能做这些并且想要在你的 Go 应用程序中存根外部依赖,你可以为第三方客户端编写一个接口,并在运行时提供接口的存根实现集成测试(在您的应用程序上使用一个标志来告诉它以“存根”模式或类似的方式运行)。

这是一个示例,说明这可能是什么样子。这是您发布的源代码文件 - 但使用的是获取第三方数据的接​​口:

type Service interface 
     GetDataFromDB(params apiParams, thirdClient ApiCient)


type Repository interface 
     GetDataFromDB(orm *gorm.DB)


type ThirdPartyDoer interface 
    Do(url string) interface

 
type DataService struct 
     repo Repository
     thirdParty ThirdPartyDoer


func (s *DataService) GetDataFromDB(params apiParams, thirdClient ApiClient) []interface 
     var result []interface
     dataFromDb := s.repo.GetDataFromDB()
     dataFromAPI := s.thirdParty.Do(url)
     result = append(result, dataFromDb)
     result = append(result, dataFromAPI)
     return result
 

然后您可以为ThirdPartyDoer 编写一个存根实现并在测试时使用它。在生产环境中运行时,您可以使用真正的第三方客户端作为ThirdPartyDoer 的实现:

type thirdPartyDoerStub struct 

func (s *thirdPartyDoerStub) Do(url string) interface 
   return "some static test data"


// ...

// Test setup:

integrationTestDataService := &DataServicerepo: realRepository, thirdParty: &thirdPartyDoerStub


// Production setup:

integrationTestDataService := &DataServicerepo: realRepository, thirdParty: realThirdParty

在启动应用程序时,您需要有一个标志来在“测试设置”和“生产设置”之间进行选择。

【讨论】:

以上是关于在golang中进行集成测试时如何模拟外部http请求api的主要内容,如果未能解决你的问题,请参考以下文章

如何在 golang 中为我的测试用例正确创建模拟 http.request?

如何在颤振集成测试中模拟 http 请求?

如何使用不同的方法多次模拟调用 AWS 服务的 Golang 函数的单元测试?

在集成测试 Play 2.4.X 中模拟外部 Web 服务调用

在 Go 中分离单元测试和集成测试

你如何在 GoLang 的模拟中模拟错误返回值?