unit-testing - 为从中读取的函数填充 os.Stdin

标签 unit-testing go testing command-line user-input

如何在我的测试中填写 os.Stdin 以获取使用扫描仪从其中读取的函数?

我使用以下功能通过扫描仪请求用户命令行输入:

func userInput() error {
    scanner := bufio.NewScanner(os.Stdin)

    println("What is your name?")
    scanner.Scan()
    username = scanner.Text()

    /* ... */
}

现在如何测试这种情况并模拟用户输入? 以下示例不起作用。标准输入仍然是空的。

func TestUserInput(t *testing.T) {
    var file *os.File
    file.Write([]byte("Tom"))
    os.Stdin = file

    err := userInput()
    /* ... */
}

最佳答案

模拟os.Stdin

os.Stdin 是一个可以修改的变量(类型为 *os.File),您可以在测试中为其分配一个新值。

最简单的方法是创建一个临时文件,其中包含您要模拟的内容作为 os.Stdin 上的输入。要创建临时文件,请使用 ioutil.TempFile() .然后将内容写入其中,并返回文件的开头。现在您可以将其设置为 os.Stdin 并执行您的测试。不要忘记清理临时文件。

我将您的 userInput() 修改为:

func userInput() error {
    scanner := bufio.NewScanner(os.Stdin)

    fmt.Println("What is your name?")
    var username string
    if scanner.Scan() {
        username = scanner.Text()
    }
    if err := scanner.Err(); err != nil {
        return err
    }

    fmt.Println("Entered:", username)
    return nil
}

你可以这样测试它:

func TestUserInput(t *testing.T) {
    content := []byte("Tom")
    tmpfile, err := ioutil.TempFile("", "example")
    if err != nil {
        log.Fatal(err)
    }

    defer os.Remove(tmpfile.Name()) // clean up

    if _, err := tmpfile.Write(content); err != nil {
        log.Fatal(err)
    }

    if _, err := tmpfile.Seek(0, 0); err != nil {
        log.Fatal(err)
    }

    oldStdin := os.Stdin
    defer func() { os.Stdin = oldStdin }() // Restore original Stdin

    os.Stdin = tmpfile
    if err := userInput(); err != nil {
        t.Errorf("userInput failed: %v", err)
    }

    if err := tmpfile.Close(); err != nil {
        log.Fatal(err)
    }
}

运行测试,我们看到一个输出:

What is your name?
Entered: Tom
PASS

另请参阅有关模拟文件系统的相关问题:Example code for testing the filesystem in Golang

简单的首选方式

还请注意,您可以将 userInput() 重构为不从 os.Stdin 读取,而是可以接收 io.Reader从中读取。这将使它更加健壮并且更容易测试。

在您的应用程序中,您可以简单地将 os.Stdin 传递给它,并且在测试中您可以将任何 io.Reader 传递给它在测试中创建/准备的,例如使用 strings.NewReader() , bytes.NewBuffer()bytes.NewBufferString() .

关于unit-testing - 为从中读取的函数填充 os.Stdin,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46365221/

相关文章:

java - 如何在 Java Spring 中模拟 RestTemplate?

go - 使用 Jetbrains GoLand IDE 运行 go simple 应用程序

testing - 如果直接访问其字段,如何模拟结构

python - 如何测试为 CBV ListView 生成的上下文中是否存在 'object_list'

unit-testing - 大型团队中的公共(public)库

java - 如何使用 JUnit 对时间相关方法进行单元测试

string - Go中数字(字符串类型)的高效反向索引

javascript - 如何为 <noscript> 标签编写自动化测试?

python - 如何对 os.walk 触发错误处理程序进行单元测试?

asp.net-mvc - ASP.NET MVC – Controller 测试的模拟成员