我正在尝试使用 fzf在 Go 代码中。我引用了给出的示例 here由作者。当我尝试为该函数编写测试时,它卡住了,因为 fzf
需要交互式输入。
代码:
func withFilter(command string, input func(in io.WriteCloser)) []string {
shell := os.Getenv("SHELL")
if len(shell) == 0 {
shell = "sh"
}
cmd := exec.Command(shell, "-c", command)
cmd.Stderr = os.Stderr
in, _ := cmd.StdinPipe()
go func() {
input(in)
in.Close()
}()
result, _ := cmd.Output()
return strings.Split(string(result), "\n")
}
func filter() []string {
filtered := withFilter("fzf -m", func(in io.WriteCloser) {
for i := 0; i < 10; i++ {
fmt.Fprintln(in, i)
time.Sleep(5 * time.Millisecond)
}
})
return filtered
}
测试:
func TestFilter(t *testing.T) {
assert.Equal(t, []string{"1", "2", "3"}, filter())
}
我尝试调试并注意到它卡在 cmd.Output()
处。通过更深入地挖掘,看起来该命令正在无限期地等待输入,但是我不确定如何以编程方式提供它。我尝试将 \n
写入 os.Stdin
但它没有用。
任何人的指点或解释将不胜感激。谢谢。
最佳答案
go 的优点:它的 io.Reader
/io.Writer
接口(interface)。
您必须提供您的withFilter
(以及扩展名filter
)方法应该从哪里读取。因此,in
必须提供它。
// example
func readFrom(reader io.Reader) {
r := bufio.NewScanner(reader)
for r.Scan() {
fmt.Println("got", r.Text())
}
fmt.Println("Done.")
}
func main() {
const input = "Now is the winter of our discontent,\nMade glorious summer by this sun of York.\n"
readFrom(strings.NewReader(input))
// okay, with stdin
readFrom(os.Stdin)
}
如您所见,第一个 readFrom
是完全可测试的,您只需将 input
变量更改为您想要测试的任何值。第二个 readFrom
只会在 stdin
关闭时返回。
解决方案是不写入os.Stdin
。将 os.Stdin
视为操作系统中的实现细节,而不是必须包含在测试中的内容。
https://play.golang.org/p/D2wzHYrV2TM (os.Stdin 在 Playground 上关闭)
关于shell - 在 Golang 中需要交互式输入的测试执行程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54470127/