Mocking 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
另请参阅有关模拟文件系统的相关问题:在 Golang 中测试文件系统的示例代码
最简单、首选的方式
另请注意,您可以重构userInput()
不读os.Stdin
,但它可能会收到一个io.Reader
从中读取。这将使它更加健壮并且更容易测试。
在您的应用程序中,您可以简单地传递os.Stdin
到它,并且在测试中你可以通过任何io.Reader
在测试中创建/准备它,例如使用strings.NewReader(), bytes.NewBuffer() or bytes.NewBufferString().