I am having difficulty writing tests for this 3rd party library I am importing. I think this is because I want my CustomClient
struct to have a client
interface instead of the *banker.Client
. This is making testing very difficult because it's hard to mock a *banker.Client
. Any ideas how I can correctly turn this into an interface? So I can easily write mock tests against it and set up a fake client?
type CustomClient struct {
client *banker.Client //I want to change this to an interface
name string
address string
}
func (c *CustomClient) SetHttpClient(httpClient *banker.Client) { //I want to accept an interface so I can easily mock this.
c.client = httpClient
}
The problem is that banker.Client is a third party client I am importing with many structs and other fields inside of it. It looks like this:
type Client struct {
*restclient.Client
Monitor *Monitors
Pricing *Pricing
Verifications *Verifications
}
The end result is that my code looks like this:
func (c *CustomClient) RequestMoney() {
_, err := v.client.Verifications.GetMoney("fakeIDhere")
}
CodePudding user response:
I think it is impossible to make it into interface directly
because we should use the member variables of the Client
.
How about making its member into interface? For example,
for _, test := []struct{}{
testVerification VerificationInterface
}{{
testVerification: v.Client.Verifications
},{
testVerification: VerficationMock
}}{
// test code here
}
CodePudding user response:
Given methods over fields on the struct, it sure wouldn't be a simple solution. However, we can try to minimize the lengthy test cases on the current package.
Add another layer (package) between your working package and banker. Simplifying the code in example to explain.
Let's say your banker
package has the following code:
type Client struct {
Verification *Verification
}
type Verification struct{}
func (v Verification) GetMoney(s string) (int, error) {
...
}
Create another package that imports the banker and has interface defined, say bankops
package:
type Bank struct {
BankClient *banker.Client
}
type Manager interface {
GetMoney(s string) (int, error)
}
func (b *Bank) GetMoney(s string) (int, error) {
return b.BankClient.Verification.GetMoney(s)
}
Note: The actual issue (test without interface) is still here in bankops package, but this is easier to test as we are only forwarding the result. Serves the purpose of unit tests.
Finally, in the current package (for me, it is main
package), we can
type CustomClient struct {
client bankops.Manager
}
func (c *CustomClient) RequestMoney() {
_, err := c.client.GetMoney("fakeIDhere")
...
}
func main() {
client := &CustomClient{
client: &bankops.Bank{
BankClient: &banker.Client{
Verification: &banker.Verification{},
},
},
}
client.RequestMoney()
}
For working example, check in Playground.
You may add the setters
or builders pattern
as you were doing in your original code snippet to make the fields (like BankerClient
) unexported.