英文:
Readline Failed in Go Test Case
问题
我正在尝试在测试用例中获取键盘输入,基本上我按照这个例子进行操作:
https://www.socketloop.com/tutorials/golang-read-input-from-console-line
在我的单元测试用例中,它总是出现"EOF"的错误,而不给我机会从键盘输入。
Go的单元测试环境有什么特殊之处吗?还是我应该寻找另一个更好的选项?
我的代码如下:
func (o *Player) consoleReadLn() (line string) {
consoleReader := bufio.NewReader(os.Stdin)
line, err := consoleReader.ReadString('\n')
if err != nil {
panic(err.Error()) // 它只会抛出: EOF
}
return
}
请注意,这是你要翻译的内容。
英文:
I'm experimenting getting keyboard input in a test case, basically I followed this example,
https://www.socketloop.com/tutorials/golang-read-input-from-console-line
and in my unit test case, it always result in error of "EOF" without giving me a chance to type in from keyboard.
Is there any special in Go unit test environment? Or I should look into another better option?
My code looks like,
func (o *Player) consoleReadLn() (line string) {
consoleReader := bufio.NewReader(os.Stdin)
line, err := consoleReader.ReadString('\n')
if err != nil {
panic(err.Error()) // it just panic: EOF
}
return
}
答案1
得分: 1
首先,你的代码需要进行修正:
import "testing/iotest"
func (o *Player) consoleReadLn() string {
consoleReader := bufio.NewReader(os.Stdin)
s := ""
for {
s1, err := consoleReader.ReadString('\n')
if err == io.EOF {
break
}
if err != nil && err != iotest.ErrTimeout {
panic("GetLines: " + err.Error())
}
s += s1
}
return s
}
因为你期望使用\n
作为字符串的换行符,所以它会返回带有EOF
(在Unix操作系统中为\n
)的数据,参见godoc bufio#Reader.ReadString:
ReadString 从输入中读取,直到遇到第一个分隔符,返回包含数据和分隔符的字符串。如果在找到分隔符之前遇到错误,ReadString 将返回错误之前读取的数据和错误本身(通常是 io.EOF)。只有当返回的数据不以分隔符结尾时,ReadString 才会返回 err != nil。对于简单的用法,Scanner 可能更方便。
然而,我建议阅读这个答案 Read from initial stdin in GO?
其次,在像go test
这样的单元测试环境中很难测试STDIN
。我找到了这封邮件,其中提到:
新的
go test
将测试与标准输入连接到/dev/null
。
所以我认为通过go test
直接测试os.Stdin
是很困难的,例如,下面的代码证实了当运行命令echo this is stdin | go test ./
时,它根本不会读取/dev/stdin
:
import "io/ioutil"
import "testing"
import "fmt"
func TestSTDIN(t *testing.T) {
bytes, err := ioutil.ReadAll(os.Stdin)
if err != nil {
t.Fatal(err)
}
fmt.Println(string(bytes))
}
以上是要翻译的内容。
英文:
Firstly, your code should be corrected to:
import "testing/iotest"
func (o *Player) consoleReadLn() string {
consoleReader := bufio.NewReader(os.Stdin)
s := ""
for {
s1, err := consoleReader.ReadString('\n')
if err == io.EOF {
break
}
if err != nil && err != iotest.ErrTimeout {
panic("GetLines: " + err.Error())
}
s += s1
}
return s
}
Because you expect using \n
as delimiter of a line of string, so it will return the data with EOF
which is \n
in Unix OS, see godoc bufio#Reader.ReadString:
> ReadString reads until the first occurrence of delim in the input, returning a string containing the data up to and including the delimiter. If ReadString encounters an error before finding a delimiter, it returns the data read before the error and the error itself (often io.EOF). ReadString returns err != nil if and only if the returned data does not end in delim. For simple uses, a Scanner may be more convenient.
However, I suggest reading this answer Read from initial stdin in GO?
Secondly, it is hard to test STDIN
in unit test context like go test
. I found this mail saying:
> the new go test
runs tests with standard input connected
to /dev/null
.
So I think it is hard to test os.Stdin
via go test
directly, for example, the following code confirmed it doesn't read /dev/stdin
at all when running command echo this is stdin | go test ./
:
import "io/ioutil"
import "testing"
import "fmt"
func TestSTDIN(t *testing.T) {
bytes, err := ioutil.ReadAll(os.Stdin)
if err != nil {
t.Fatal(err)
}
fmt.Println(string(bytes))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论