Rafael
Rafael

Reputation: 153

How to test write to a file with functions Write, WriteAt and Truncate in Go

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

Answers (1)

eik
eik

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

Related Questions