【问题标题】:How can I write a Go test that writes to stdin?如何编写写入标准输入的 Go 测试?
【发布时间】:2016-05-16 23:23:04
【问题描述】:

假设我有一个简单的应用程序,它从标准输入读取行并将其简单地回显到标准输出。例如:

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func main() {
    reader := bufio.NewReader(os.Stdin)
    for {
        fmt.Print("> ")
        bytes, _, err := reader.ReadLine()
        if err == io.EOF {
            os.Exit(0)
        }
        fmt.Println(string(bytes))
    }
}

我想编写一个写入标准输入的测试用例,然后将输出与输入进行比较。例如:

package main

import (
    "bufio"
    "io"
    "os"
    "os/exec"
    "testing"
)

func TestInput(t *testing.T) {
    subproc := exec.Command(os.Args[0])
    stdin, _ := subproc.StdinPipe()
    stdout, _ := subproc.StdoutPipe()
    defer stdin.Close()

    input := "abc\n"

    subproc.Start()
    io.WriteString(stdin, input)
    reader := bufio.NewReader(stdout)
    bytes, _, _ := reader.ReadLine()
    output := string(bytes)
    if input != output {
        t.Errorf("Wanted: %v, Got: %v", input, output)
    }
    subproc.Wait()
}

运行go test -v 给了我以下信息:

=== RUN   TestInput
--- FAIL: TestInput (3.32s)
    echo_test.go:25: Wanted: abc
        , Got: --- FAIL: TestInput (3.32s)
FAIL
exit status 1

我显然在这里做错了什么。我应该如何测试这种类型的代码?

【问题讨论】:

    标签: unit-testing go


    【解决方案1】:

    您可以定义一个以io.Readerio.Writer 作为参数并执行您希望它执行的任何操作的函数,而不是使用stdinstdoutmain 中执行所有操作。 main 然后可以调用该函数,您的测试函数可以直接测试该函数。

    【讨论】:

    • 是的,我已经考虑过了,我希望这是我必须要做的。我只是想知道是否有办法直接访问 main 的标准输入/标准输出。
    【解决方案2】:

    这是一个写入标准输入并从标准输出读取的示例。请注意,它不起作用,因为输出首先包含“>”。不过,您可以根据需要对其进行修改。

    func TestInput(t *testing.T) {
        subproc := exec.Command("yourCmd")
        input := "abc\n"
        subproc.Stdin = strings.NewReader(input)
        output, _ := subproc.Output()
    
        if input != string(output) {
            t.Errorf("Wanted: %v, Got: %v", input, string(output))
        }
        subproc.Wait()
    }
    

    【讨论】:

    • 我已经从我的输出中删除了 "> " 并使用了你的 TestInput 函数。我得到一系列大约 100 次重复失败,看起来像这样: === RUN TestInput --- FAIL: TestInput (5.17s) echo_test.go:36: Wanted: abc , Got: --- FAIL: TestInput (5.15 s) echo_test.go:36: Wanted: abc, Got: --- FAIL: TestInput (5.13s) echo_test.go:36: Wanted: abc ...等等。
    • 删除“>”时对我来说效果很好。您是否提供了正确的运行命令?
    • Go 创建一个临时目录来运行测试。当我打印 os.Args[0] 这就是我得到的:/tmp/go-build208836783/command-line-arguments/_test/main.test。您需要先使用go install ./... 安装程序,使其以您的路径结尾,然后运行相关命令。我的主文件是 elyk/main.go 所以我运行的命令是“elyk”
    • 是的。那么为什么它不适用于为测试运行构建的二进制文件呢?
    • 运行go test 时,go 创建一个测试二进制文件。它创建一个使用 goroutine 运行所有文件测试的 main,并编译它。这与您的程序不同。关于为什么测试二进制文件与go install 生成的二进制文件不同的更多详细信息:golang.org/cmd/go/#hdr-Test_packages
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-31
    • 2019-02-27
    • 2021-09-27
    • 2012-08-24
    • 1970-01-01
    • 1970-01-01
    • 2011-07-23
    相关资源
    最近更新 更多