【问题标题】:How to mock external http request api when integration test in golang在golang中进行集成测试时如何模拟外部http请求api
【发布时间】: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 := &params{Id: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客户端会返回随机数据。
在这种情况下,我该怎么办?
如果我想模拟客户端以获得稳定的数据进行测试,如何在集成测试中伪造它?

【问题讨论】:

标签: api unit-testing go testing integration-testing


【解决方案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 := &DataService{repo: realRepository, thirdParty: &thirdPartyDoerStub{}}


// Production setup:

integrationTestDataService := &DataService{repo: realRepository, thirdParty: realThirdParty}

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

【讨论】:

    猜你喜欢
    • 2019-08-19
    • 2019-05-21
    • 2017-01-12
    • 1970-01-01
    • 1970-01-01
    • 2015-03-20
    • 1970-01-01
    • 2015-12-14
    • 1970-01-01
    相关资源
    最近更新 更多