在Go测试用例中,Readline失败了。

huangapple go评论91阅读模式
英文:

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))
}

huangapple
  • 本文由 发表于 2015年8月8日 20:17:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/31893044.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定