如何在我的测试中填写os.Stdin中使用扫描仪从中读取的功能?
我要求使用以下功能通过扫描仪输入用户命令行:
func userInput() error { scanner := bufio.NewScanner(os.Stdin) println("What is your name?") scanner.Scan() username = scanner.Text() /* ... */ }
现在如何测试这种情况并模拟用户输入?以下示例不起作用。Stdin还是空的。
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.File
最简单的方法是使用您要模拟的内容作为输入创建一个临时文件os.Stdin。要创建临时文件,请使用ioutil.TempFile()。然后将内容写入其中,并返回到文件的开头。现在,您可以将其设置为os.Stdin并执行测试。不要忘记清理临时文件。
ioutil.TempFile()
我将您修改userInput()为:
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
另请注意,您可以重构userInput()为不读取os.Stdin,但是可以接收io.Reader到读取的内容。这将使它更健壮并且更容易测试。
io.Reader
在您的应用程序,你可以简单地传递os.Stdin给它,并在测试中,你可以通过任何io.Reader它创建/在测试准备,例如使用strings.NewReader(),bytes.NewBuffer()或bytes.NewBufferString()。
strings.NewReader()
bytes.NewBuffer()
bytes.NewBufferString()