I have a service to get db data and get others data from third party api.
Like this:
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 := ¶ms{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)
}
And third party api client will return random data.
In this situation, what should I do ?
If I want to mock client to get stable data to test, how to fake it in integration test ?
CodePudding user response:
I am assuming "integration test" means you will be running your entire application and then testing the running instance together with its dependencies (in your case a database & third party service). I assume you do not mean unit testing.
For integration tests you have a few options. In my case, usually I would integration test including whatever the third party client is connecting to (no mocking) because I want to test the integration of my service with the third party one. Or if that is not possible I might write a simple stub application with the same public interface as the third party service and run it on localhost (or somewhere) for my application to connect to during testing.
If you don't want to or can't do either of those and want to stub the external dependency inside your Go application, you can write an interface for the third party client and provide a stubbed implementation of the interface when running integration tests (using a flag on your application to tell it to run in "stubbed" mode or something of that nature).
Here's an example of what this might look like. Here's the source code file you posted - but using an interface for getting the third party data:
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
}
Then you can write a stub implementation for ThirdPartyDoer
and use it when testing. When running in Production you can use the real third party client as ThirdPartyDoer
's implementation:
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}
You would need to have a flag to select between "test setup" and "production setup" when starting your application.