用于测试的内存文件

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

In-memory file for testing

问题

在Go语言中,可以使用bytes.Bufferstrings.Builder来创建内存文件进行单元测试。

对于文件读取的测试,可以使用bytes.NewBufferString函数创建一个*bytes.Buffer对象,然后将测试数据写入该对象。例如:

func TestParseFunction(t *testing.T) {
    input := bytes.NewBufferString(`
    line1
    line2
    line3
    `)
    parsedContents := parseFunction(input)
    expectedContents := []string{"line1", "line2", "line3"}  // 或者其他适当的期望结果
    if !reflect.DeepEqual(parsedContents, expectedContents) {
        t.Errorf("Unexpected parsed contents. Got %v, expected %v", parsedContents, expectedContents)
    }
}

对于文件输出的测试,可以使用strings.Builder来模拟一个输出文件。例如:

func TestWriteFunction(t *testing.T) {
    var output strings.Builder
    writeFunction(&output, []string{"line1", "line2", "line3"})
    expectedOutput := `
    line1
    line2
    line3
    `
    if output.String() != expectedOutput {
        t.Errorf("Unexpected output. Got %v, expected %v", output.String(), expectedOutput)
    }
}

这样就可以在内存中进行文件读写的单元测试了。

英文:

How does one create in-memory files for unit testing in Go?

In Python, I test reading from a file or writing to a file using io.BytesIO or io.StringIO. For example, to test a file parser, I would have

def test_parse_function():
    infile = io.StringIO('''\
line1
line2
line3
''')
    parsed_contents = parse_function(infile)
    expected_contents = ['line1', 'line2', 'line3']  # or whatever is appropriate
    assert parsed_contents == expected_contents

Similarly for file output, I would have something like the following:

def test_write_function():
    outfile = io.StringIO()
    write_function(outfile, ['line1', 'line2', 'line3'])
    outfile.seek(0)
    output = outfile.read()
    expected_output = '''\
line1
line2
line3
'''
    assert output == expected_output

答案1

得分: 23

你可以使用Buffer

一般来说,在你的代码中使用io.Readerio.Writer接口是一个好主意(Buffer同时实现了这两个接口),以处理输入/输出。这样你可以以相同的方式处理各种输入/输出方法(本地文件、内存缓冲区、网络连接...),而不需要知道在特定函数中处理的是什么。这使得代码更加抽象化,测试也更加简单。


以下是一个使用简单函数的示例:

函数定义:

// mypkg 项目 mypkg.go
package mypkg

import (
    "bufio"
    "io"
    "strings"
)

func MyFunction(in io.Reader, out io.Writer) {
    rd := bufio.NewReader(in)
    str, _ := rd.ReadString('\n')
    io.WriteString(out, strings.TrimSuffix(str, "\n")+" was input\n")
}

在程序中使用该函数:

package main

import (
	"mypkg"
	"os"
)

func main() {
	mypkg.MyFunction(os.Stdin, os.Stdout)
}

测试:

// mypkg 项目 mypkg_test.go
package mypkg

import (
	"bytes"
	"testing"
)

func TestMyFunction(t *testing.T) {
	ibuf := bytes.NewBufferString("hello\n")
	obuf := bytes.NewBufferString("")
	MyFunction(ibuf, obuf)
	if obuf.String() != "hello was input\n" {
		t.Fail()
	}
}
英文:

You can use a Buffer.

In general, it's a good idea to use io.Reader and io.Writer interfaces in your code (Buffer implements both) to deal with IO. That way you can deal with various methods of input/output (local file, memory buffer, network connection...) in the same way, without knowing what you are dealing with in the specific function you're using. It makes it more abstract and makes testing trivial.


Example of use with a trivial function:

Function definition:

// mypkg project mypkg.go
package mypkg

import (
    "bufio"
    "io"
    "strings"
)

func MyFunction(in io.Reader, out io.Writer) {
    rd := bufio.NewReader(in)
    str, _ := rd.ReadString('\n')
    io.WriteString(out, strings.TrimSuffix(str, "\n")+" was input\n")
}

Function use within a program:

package main

import (
	"mypkg"
	"os"
)

func main() {
	mypkg.MyFunction(os.Stdin, os.Stdout)
}

Test:

// mypkg project mypkg_test.go
package mypkg

import (
	"bytes"
	"testing"
)

func TestMyFunction(t *testing.T) {
	ibuf := bytes.NewBufferString("hello\n")
	obuf := bytes.NewBufferString("")
	MyFunction(ibuf, obuf)
	if obuf.String() != "hello was input\n" {
		t.Fail()
	}
}

答案2

得分: 5

如果你需要一个io.ReadSeeker,并且不需要写入权限,可以使用bytes.Reader

import "bytes"

data := []byte("success")
readSeeker := bytes.NewReader(data)

这在像http.ServeContent()这样的情况下非常有用。

或者,更简单地:

import "strings"

readSeeker := strings.NewReader("success")
英文:

If you need an io.ReadSeeker, and you don't need write access, use bytes.Reader:

import "bytes"

data := []byte("success")
readSeeker := bytes.NewReader(data)

This is useful for things like http.ServeContent().

Or, even more simply:

import "strings"

readSeeker := strings.NewReader("success")

答案3

得分: 3

如在《Go语言中的实用和有效测试》中所提到的,你可以使用spf13/afero进行文件抽象,从而使测试更加简单。

该库有一个使用Afero进行测试的部分:

使用模拟文件系统进行测试有很大的好处。

它在每次初始化时都具有完全空白的状态,并且可以轻松地在任何操作系统上进行重现。您可以随心所欲地创建文件,并且文件访问速度快,同时也可以避免删除临时文件、Windows文件锁定等烦人问题。MemMapFs后端非常适合测试。

  • 比在磁盘上执行I/O操作要快得多
  • 避免安全问题和权限问题
  • 更多的控制权。放心地执行'rm -rf /'
  • 测试设置更加容易
  • 不需要测试清理

它使用了一个完全原子的内存后备文件系统(MemMapFs
它完全并发,并且可以在Go协程中安全地工作。

英文:

As mentioned in "Pragmatic and Effective Testing in Go", you can use spf13/afero for file abstraction which leads to easier tests.

That library has a Using Afero for Testing:

> There is a large benefit to using a mock filesystem for testing.

> It has a completely blank state every time it is initialized and can be easily reproducible regardless of OS.
You could create files to your heart’s content and the file access would be fast while also saving you from all the annoying issues with deleting temporary files, Windows file locking, etc.
The MemMapFs backend is perfect for testing.

> - Much faster than performing I/O operations on disk

  • Avoid security issues and permissions
  • Far more control. 'rm -rf /' with confidence
  • Test setup is far more easier to do
  • No test cleanup needed

It uses a fully atomic memory backed filesystem (MemMapFs).
It is fully concurrent and will work within go routines safely.

huangapple
  • 本文由 发表于 2016年10月29日 12:35:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/40316052.html
匿名

发表评论

匿名网友

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

确定