Reputation: 13
I am currently writing a workflow in Go that uses Google's API go client. I'm relatively new to Go and am having trouble unit testing the client's services. Here is an example method that enables an API in a Google Cloud Project.
func (gcloudService *GCloudService) EnableApi(projectId string, apiId string) error {
service, err := servicemanagement.New(gcloudService.Client)
if err != nil {
return err
}
requestBody := &servicemanagement.EnableServiceRequest{
ConsumerId: consumerId(projectId),
}
_, err = service.Services.Enable(apiId, requestBody).Do()
if err != nil {
return err
}
return nil
}
GCloudService
is a simple struct that holds a Client.
type GCloudService struct {
Client *http.Client
}
This is my attempt at testing this method.
var (
mux *http.ServeMux
client *http.Client
server *httptest.Server
)
func setup() {
// test server
mux = http.NewServeMux()
server = httptest.NewServer(mux)
// client configured to use test server
client = server.Client()
}
func teardown() {
server.Close()
}
func TestGCloudService_EnableApi(t *testing.T) {
setup()
defer teardown()
projectName := "test"
apiId := "api"
testGcloudService := &GCloudService{
Client: client,
}
path := fmt.Sprintf("/v1/services/{%s}:enable", apiId)
mux.HandleFunc(path,
func(w http.ResponseWriter, r *http.Request) {
// test things...
})
err := testGcloudService.EnableApi(projectName, apiId)
if err != nil {
t.Errorf("EnableApi returned error: %v", err)
}
}
However, when I run this test it still hits the real Google endpoint instead of my localhost server because EnableApi uses the servicemanagement service which is configured with the API's base URL. How do I refactor this to call my server instead of the API? I am hoping to avoid mocking the entire servicemanagement service if possible.
Upvotes: 1
Views: 1905
Reputation: 4914
What I'd recommend is creating your own interface that wraps the google api client and extract the methods that you're interested in.
type MyWrapperClient interface {
SomeMethodWithCorrectReturnType()
}
type myWrapperClient struct {
*GCloudService.Client // or whatever
}
In the directory I'd then run:
mockery -name=MyWrapperClient
inside the directory (after installing mockery)
and then you can access your mocked version. Then on object creation substitute your mock in for your client - as the interface and the mock have the same methods they are interchangeable. Then you can test whether methods are called with specific params - leaving the google api client code alone.
More information on the mockery library is here: https://github.com/vektra/mockery
This article solves your same problem and it's absolutely fantastic in explaining how to mock and abstract your concerns away.
https://medium.com/agrea-technogies/mocking-dependencies-in-go-bb9739fef008
Upvotes: 1
Reputation: 1063
Make the base url in your servicemanagement service configurable or overwritable, and if that is hidden for you, then your code is not written for test convenience, change that, and if not possible, complain to who is responsible. If that does not help, take a deep breath, and write a mock service, which is mostly not needed to be very complicated
Upvotes: 0