In my Go code, I have to use filepath.Abs() several times, which may lead to different errors that my method returns.
func (s *service) myFunc(path string) error {
dir := s.Component().Dir()
absDir, err := filepath.Abs(dir)
if err != nil {
return my_errors.NewFailedToGetAbsoluteComponentDir()
}
absPath, err := filepath.Abs(path)
if absPath != nil {
return my_errors.NewFailedToGetAbsPath()
}
// more code...
return nil
}
In my unit test, I want to test it, but the only way I can think of is to inject filepath.Abs as a dependency into my struct.
Is there any other way I did not think of? Or do you think that this kind of test is unnecessary?
If we look at the source code for the filepath.Abs
function in the standard library, we can see when it returns an error, and then try to trigger that condition in our tests. filepath.Abs
has different implementations depending on which target OS it's compiled for, but the Unix implementation, for example, looks like this:
func unixAbs(path string) (string, error) {
if IsAbs(path) {
return Clean(path), nil
}
wd, err := os.Getwd()
if err != nil {
return "", err
}
return Join(wd, path), nil
}
So the only time it will ever return an error is when os.Getwd()
returns an error. An easy way to make os.Getwd()
return an error is to ensure that your current working directory doesn't exist. This can be done in a test as so:
dir, _ := os.MkdirTemp("", "") // Create a temporary directory
os.Chdir(dir) // Change to that directory
os.RemoveAll(dir) // Delete that directory
fmt.Println(os.Getwd()) // This will now return an error
Now this has the problem that it changes the working directory for the entire process, which could interfere with other tests. So it's important to both reset the working directory after this test runs, and also to make sure that no other tests that depend on the working directory run at the same time.
To reset it, put this at the beginning of your test:
origWd, _ := os.Getwd()
t.Cleanup(func() {
os.Chdir(origWd)
})
And to make sure no other conflicting tests run at the same time, don't call t.Parallel()
in your test.
Is it worth it to test this? Usually not. How often is your working directory likely to be invalid? Under most circumstances, never. If that describes you, I simply wouldn't test this part of your code.
However, if you're building a CLI tool, for example, where the working directory is in constant flux or often unknown, then such a test may indeed be worth it.
Just make sure your test provides some actual value, before you go to this much effort :)
I've made a video discussing this question, and the general question for anyone interested in a longer discussion of the topic: Answering StackOverflow: How do you test filepath.Abs in Go?