Golang: Creating temporary directory for testing a file reading function

Viewed 465

I'm trying to write a test for a file reading function. The function accepts directory path & start scanning to categorize files with the sub-directories.

func FileScan(dir string) (map[string][]string, error) {
    var dataset = make(map[string][]string)

    files, err := ioutil.ReadDir(dir)
    if err != nil {
        return nil, err
    }

    for _, file := range files {
        if file.IsDir() {
            dirFiles, err := ioutil.ReadDir(fmt.Sprintf("%s/%s", dir, file.Name()))
            if err != nil {
                return nil, err
            }

            for _, dirFile := range dirFiles {
                if !dirFile.IsDir() {
                    dataset[file.Name()] = append(dataset[file.Name()], dirFile.Name())
                }
            }
        }
    }
    return dataset, nil
}

For testing, I created a temporary directory next to the test file & put some sub-directories & files insides them, then start to test the function & call a cleaner function via defer to delete the directory after test.

Is this a good practice? or maybe it's better to pass an array of []fs.FileInfo instead of directory path, so I can implement a mocked FileInfo in testing.

1 Answers

You can try to make your tests cleaner, faster and avoid touching the filesystem if you modify your code in a way it could be tested with https://pkg.go.dev/testing/fstest@go1.17.3#MapFS Side note: it's recommended to use os.ReadDir instead of ioutil.ReadDir

Here is a working example with the minimal modification of your code (playground link):

package main

import (
    "fmt"
    "io/fs"
    "log"
    "path"
    "reflect"
    "testing/fstest"
)

func main() {
    var myFiles fstest.MapFS = make(map[string]*fstest.MapFile)
    myFiles["test_dir/i_am_a_file"] = &fstest.MapFile{}
    myFiles["test_dir/i_am_a_directory/add_me_to_map"] = &fstest.MapFile{}
    myFiles["test_dir/i_am_a_directory_too/add_me_to_map_too"] = &fstest.MapFile{}
    myFiles["test_dir/i_am_a_directory_too/and_me"] = &fstest.MapFile{}
    myFiles["test_dir/i_am_a_directory_too/do_not_add_me_to_map/"] = &fstest.MapFile{}
    m, err := FileScan(myFiles, "test_dir")
    if err != nil {
        log.Fatalln("Test failed:", err)
    }
    expectedMap := map[string][]string{
        "i_am_a_directory":     {"add_me_to_map"},
        "i_am_a_directory_too": {"add_me_to_map_too", "and_me"},
    }

    if !reflect.DeepEqual(expectedMap, m) {
        log.Fatalf("m: expected  = %v, observed = %v", 2, expectedMap, m)
    }
    fmt.Println("OK")
}

func FileScan(fileSystem fs.FS, dir string) (map[string][]string, error) {
    var dataset = make(map[string][]string)
    files, err := fs.ReadDir(fileSystem, dir)
    if err != nil {
        return nil, err
    }
    for _, file := range files {
        if !file.IsDir() {
            continue
        }
        dirFiles, err := fs.ReadDir(fileSystem, path.Join(dir, file.Name()))
        if err != nil {
            return nil, err
        }
        for _, dirFile := range dirFiles {
            if dirFile.IsDir() {
                continue
            }
            dataset[file.Name()] = append(dataset[file.Name()], dirFile.Name())
        }

    }
    return dataset, nil
}

Related