I have a below function tryGet() to unit test:
type config struct {
Key string `json:"key"`
Client todo.Client `json:"client"`
}
var instance *config
func (c *config) tryGet() error {
client := &http.Client{}
tClient := Client{"http://url", client}
configValues := config{"Key", tClient}
Instance := &configValues
err := Instance.Client.perform("GET", header)
return nil
}
// External library in package named "todo" has the below structs and functions
package todo
type Client struct {
BaseURL string
HTTPClient *http.Client
}
func (client *Client) perform() error {
return nil
}
I am finding a hard time to mock the Client and perforn in external package todo
You can mock the function as follow
type myImpl todo.Client
func (client *myImpl) perform() error {
// do what you want to assert in the test
return nil
}
And then you will use myImpl whenever you have to use todo.Client
if you are using a function with a parameter of type todo.Client, it will not work if you pass an argument of type myImpl. It will throw an error:
cannot use client (type myImpl) as type todo.Client in field value
To solve this issue, an interface can be created
type Client interface {
perform() error
}
Now the type Client should replace the type todo.Client
of the function to be unit tested.
type config struct {
Url string `json:"url"`
Client Client `json:"client"`
}
With this change the above code which supply an implementation myImpl
of the interface Client
should work
If the external library is not under your control, which I assume is the case, then you should assume that the code within is tested, therefore you should create the boundary at a point that you have control of the code.
To do this you should create the interface at the config struct boundary.
type ClientInterface interface {
perform() error
}
type config struct {
Url string `json:"url"`
Client ClientInterface `json:"client"`
}
var instance *config
func (c *config) tryGet() error {
err := c.Client.perform("GET", header)
return nil
}
By doing it this way, you don't care about testing the lower level code base and you just care that this module has a perform function and that given certain conditions your code behaves correctly.
You can then create a mock todo.Cient struct that you can replace the normal one with and have it return all sorts of things and behaviors to test your code.