Let's say I have a package with the following code:
package paths
type FilePath struct {
PathA string
}
func (c FilePath) GetPathA() string {
if err := PathExists(PathA); err != nil {
return ""
}
return PathA + "foo"
}
func PathExists(p string) error {
// call os and file methods
return err
}
How do I mock out the PathExists dependency to test FilePath? Also, method PathExists is being used by a lot of other packages as well. (I am open to suggestions of refactoring this to make it test friendly, keeping the following pointers in mind)
I have come across a few different approaches but none of them seems intuitive or idiomatic to me.
Have a global variable
PE := PathExistsin the package; inGetPathA, callerr := PE(PathA)and in the test overwritePEwith a mock method.Issue: If test package is something like paths_test, I will have to export
PEwhich allows clients of the package to overwrite it as well.Make
PathExistsa field ofFilePathand mock the field in test.Issue: Clients when using the package, will have to initialize
PathExistsfield, or I provide a constructor of the formNewFilePath(PathtA string)which initializes the fields for me. In the actual use case there are a lot of fields, hence this approach fails as well.Use an interface and embed it within the struct. When client uses it initialize with the actual method and for test mock it.
type PathExistser interface{ PathExists(p string) error } type FilePath struct{ PathA string PathExister } type Actual struct{} func (a Actual) PathExists(p string) error { return PathExists(p) }Issue: Client again needs to provide the right implementation of the interface.
I have learnt of few more approaches doing something simimlar to the above options, such as make the method PathExists an argument for GetPathA, etc. All have the same concerns. Basically, I don't want the users of this package to have to figure out what should be the right input parameter to make sure the struct works as expected. Neither do I want the users to overwrite the behaviour PathExists.
This seems like a very straightforward problem and I seem to be missing something very funamental about go testing or mocking. Any help would be appreciated, thanks.
Method names are just for example. In reality GetPathA or PathExists would be way more complex.