在Golang中测试文件系统的示例代码

时间:2017-05-11 09:55:18

标签: unit-testing go

我正在尝试为与文件系统交互的函数编写单元测试,我希望能够在测试期间模拟文件系统。

下面的代码是this问题的答案,在那里您将创建一个在测试期间使用的文件系统接口,但我是Go的新手,并且正在努力弄清楚如何使用它。 / p>

有人能够提供一个如何在测试中使用此接口的示例吗?

var fs fileSystem = osFS{}

type fileSystem interface {
    Open(name string) (file, error)
    Stat(name string) (os.FileInfo, error)
}

type file interface {
    io.Closer
    io.Reader
    io.ReaderAt
    io.Seeker
    Stat() (os.FileInfo, error)
}

// osFS implements fileSystem using the local disk.
type osFS struct{}

func (osFS) Open(name string) (file, error)        { return os.Open(name) }
func (osFS) Stat(name string) (os.FileInfo, error) { return os.Stat(name) }

2 个答案:

答案 0 :(得分:4)

您不能忘记的一件重要事情:如果与文件系统交互的代码通过上面提供的文件系统接口(filesystem)使用{{1}进行,则只能模拟文件系统全局变量(或测试代码可以更改的其他fs值,例如传递的filesystem参数)。

让我们看看这样一个示例函数:

fs

这个简单的func getSize(name string) (int64, error) { stat, err := fs.Stat(name) if err != nil { return 0, err } return stat.Size(), nil } 函数返回由其名称指定的文件的大小,如果getSize()失败则返回错误(返回错误)。

现在让我们编写一些完全涵盖此filesystem.Stat()函数的单元测试。

我们需要什么

我们需要一个模拟的getSize()版本,进行模拟,以便它实际上不与文件系统交互,但在调用filesystem的方法时返回合理数据(filesystem在我们的例子中)。为了最简单的模拟filesystem.Stat()(或任何界面),我们会在filesystem中嵌入filesystem,因此我们“继承”其所有方法,我们只需要模拟实际使用的内容通过可测试的代码。请注意,调用其他方法会导致运行时出现混乱,因为我们不会给这个嵌入式mockedFS提供合理的非nil值,但是为了测试它不需要。 / p>

由于filesystem返回值os.FileInfo(除了错误),这是一个接口(并且它的实现不是从os包导出的),我们还需要模拟filesystem。这将是os.FileInfo,我们将非常类似于模拟mockedFileInfo:我们将嵌入接口类型filesystem,所以实际上我们只需要实现{{1} },因为这是testable os.FileInfo函数调用的唯一方法。

准备/设置模拟文件系统

一旦我们有了模拟类型,我们就必须设置它们。由于FileInfo.Size()使用全局getSize()变量与文件系统进行交互,因此我们需要将getSize()的值分配给此全局fs变量。在这样做之前,建议保存旧值,并在完成测试后正确恢复旧值:“cleanup”。

由于我们完全想要测试mockedFS(包括错误情况),我们为我们的fs提供了控制是否应该返回错误的能力,并且能够告诉它如果我们不想要任何错误,请返回。

在进行测试时,我们可以操纵getSize()的“状态”,使其行为符合我们的需要。

和测试(ing)代码

不用多说,完整的测试代码:

mockedFS

答案 1 :(得分:1)

另一个选项是 testing/fstest 包:

package main
import "testing/fstest"

func main() {
   m := fstest.MapFS{
      "hello.txt": {
         Data: []byte("hello, world"),
      },
   }
   b, e := m.ReadFile("hello.txt")
   if e != nil {
      panic(e)
   }
   println(string(b) == "hello, world")
}

https://golang.org/pkg/testing/fstest