A better practice is to not rely on concrete types (e.g. os.File), but use interfaces instead that describe the functionality you want to use the file for.
E.g. if you have a function that takes a file because it wants to read from it, use io.Reader instead:
func process(r io.Reader) error {
// ...
}
Similarly, if you want to write to the file, use io.Writer, or if you want to do both, use io.ReadWriter or io.ReadWriteCloser. You may pass an *os.File value to these functions, because *os.File implements those interfaces.
The benefit of this is that you can call these functions with any values that implement the interface. If you want to test these functions, you may pass an in-memory bytes.Buffer which implements io.Reader and io.Writer, and whose content you can construct manually, at runtime, for example:
buf := &bytes.Buffer{}
buf.Write([]byte{1, 2, 3})
buf.WriteString("Hello")
Here buf will contain the bytes 1, 2, 3 and the string "Hello". After that you may pass buf where a reader or writer is needed, e.g.:
process(buf)
See similar / related questions and examples:
Fill os.Stdin for function that reads from it
Example code for testing the filesystem in Golang
[]byteor abytes.Bufferwhich implementsio.Readerandio.Writer, so you can use it to read and write just like a file.test cases, where I need a dummy encoded bytes of File(but don't want to create it) and need to check with other data. Otherwise I have to create a file and then perform the operation, but I don't have definite scenario to delete it(though I can't keep it )os.Filetype but use interfaces instead (io.Reader,io.Writerand similar). That way no matter if you pass a*bytes.Bufferor an*os.File, it will work with both.