Golang:为测试文件读取函数创建临时目录

huangapple go评论67阅读模式
英文:

Golang: Creating temporary directory for testing a file reading function

问题

我正在尝试为一个文件读取函数编写测试。该函数接受目录路径并开始扫描以将文件分类到子目录中。

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
}

为了进行测试,我在测试文件旁边创建了一个临时目录,并在其中放置了一些子目录和文件,然后开始测试该函数,并通过defer调用一个清理函数来在测试结束后删除该目录。

这是一个好的做法吗?或者也许最好传递一个[]fs.FileInfo数组而不是目录路径,这样我可以在测试中实现一个模拟的FileInfo

英文:

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

得分: 1

你可以尝试通过修改代码的方式,使得你的测试更加清晰、更快,并且避免触碰文件系统。你可以使用https://pkg.go.dev/testing/fstest@go1.17.3#MapFS来测试修改后的代码。

附注:建议使用os.ReadDir而不是ioutil.ReadDir,具体可以参考这里

以下是对你的代码进行最小修改后的工作示例(playground链接):

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
}

英文:

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
}

huangapple
  • 本文由 发表于 2021年11月14日 17:04:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/69961635.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定