Reputation: 153
I'd like to test a function in Golang that write to a file using three different methods: Write
, WriteAt
and Truncate
. The method I know is to use buffer, but buffer's method Truncate
is diferent from file method.
This is the code that write to a file using three functions: Write, WriteAt and Truncate
package main
import (
"io"
"os"
)
type Truncater interface {
Truncate(size int64) error
}
type WriterFull interface {
io.Writer
io.WriterAt
Truncater
}
func main() {
fileName := "myFile"
file, _ := os.Create(fileName)
defer file.Close()
WriteToTheFile(file)
}
func WriteToTheFile(file WriterFull) {
file.Write([]byte("Ny text full of words"))
file.WriteAt([]byte("M"), 0)
file.Truncate(6)
}
Accordingly to this source, I need bytes.Buffer
to test my function WriteToTheFile(file WriterFull)
, the *_test.go file
package main
import (
"bytes"
"testing"
)
func TestWriteToTheFile(t *testing.T) {
var buffer bytes.Buffer
buffer.WriteString("Not my text")
WriteToTheFile(&buffer)
}
I get the error
cannot use &buffer (value of type *bytes.Buffer) as WriterFull value in argument to WriteToTheFile: *bytes.Buffer does not implement WriterFull (wrong type for method Truncate)
have Truncate(int)
want Truncate(int64) errorcompilerInvalidIfaceAssign
As far as I know, it is not possible to create an interface with two equaly named functions, and file
and buffer
are incompatible, while the first use Truncate(int64)
the second use have Truncate(int)
.
How to properly perform tests in a function that use the three functions from a var file
Write
, WriteAt
and Truncate
?
Upvotes: 0
Views: 254
Reputation: 4610
If you want to test special interactions with files, using an in-memory filesystem seems beneficial:
package main
import (
"testing"
"github.com/spf13/afero"
)
func TestWriteToTheFile(t *testing.T) {
t.Parallel()
testFs := afero.NewMemMapFs()
file, _ := afero.TempFile(testFs, "/", "*")
fileName := file.Name()
_, _ = file.WriteString("Not my text")
WriteToTheFile(file)
file.Close()
got, _ := afero.ReadFile(testFs, fileName)
expected := "Mot my"
if string(got) != expected {
t.Errorf("Got: %q, expected: %q", string(got), expected)
}
}
There are other implementations of in-memory file systems, this is just an example.
Note that you should add error handling to the test and your code.
Also, as @Volker correctly remarks, it might be worthwhile to use a real file system for testing (Go Playground):
package main
import (
"os"
"testing"
)
func TestWriteToTheFile(t *testing.T) {
t.Parallel()
file, _ := os.CreateTemp("", "*")
fileName := file.Name()
defer os.Remove(fileName)
_, _ = file.WriteString("Not my text")
WriteToTheFile(file)
file.Close()
got, _ := os.ReadFile(fileName)
expected := "Mot my"
if string(got) != expected {
t.Errorf("Got: %q, expected: %q", string(got), expected)
}
}
Upvotes: 1