[英]How to test nested input in Go
I have function for getting user input using os.Stdin
我有使用os.Stdin
获取用户输入的功能
func (i input) GetInput(stdin io.Reader) (string, error) {
reader := bufio.NewReader(stdin)
data, err := reader.ReadString('\n')
if err != nil {
return "", fmt.Errorf("get input error: %w", err)
}
return strings.ReplaceAll(data, "\n", ""), nil
}
In my programm I need to have 2 inputs:在我的程序中,我需要有 2 个输入:
name,err := GetInput(os.Stdin)
if err != nil {
// error handling.....
}
switch name {
case "test":
//do something...
age, err := GetInput(os.Stdin)
if err != nil {
// error handling.....
}
fmt.Println(age)
case "another":
// Here another input
}
It it possible to write unit tests for that case?可以为这种情况编写单元测试吗? For testing one user input I use this snippet and it works:为了测试一个用户输入,我使用了这个代码片段并且它有效:
var stdin bytes.Buffer
stdin.Write([]byte(fmt.Sprintf("%s\n", tt.input)))
GetInput(stdin)
But it didn't work with 2 nested inputs但它不适用于 2 个嵌套输入
Maybe consider having a function that returns a specific type as a result and put it into a separate package.也许考虑拥有一个返回特定类型作为结果的函数,并将其放入一个单独的包中。
Since I see name
and age
mentioned, perhaps we can assume a concrete type like Person
for illustration.由于我看到提到了name
和age
,也许我们可以假设一个具体的类型,例如Person
来进行说明。
It is important to note that we want to include the actual reader as a parameter and not have a hard coded reference to os.Stdin
.重要的是要注意,我们希望将实际的阅读器作为参数包含在内,而不是对os.Stdin
进行硬编码引用。 This makes the mocking of nested inputs possible in the first place.这使得嵌套输入的模拟成为可能。
With this, the signature of the method could look something like the following:这样,该方法的签名可能类似于以下内容:
func NestedInput(input io.Reader) (*Person, error)
The corresponding type could be:对应的类型可以是:
type Person struct {
Name string
Age int
}
If one now combines your code snippets to a complete GO file with the name input.go
in a separate directory, it might look something like this:如果现在将您的代码片段组合成一个完整的 GO 文件,名称为input.go
,位于单独的目录中,它可能看起来像这样:
package input
import (
"bufio"
"fmt"
"io"
"strconv"
"strings"
)
func getInput(reader *bufio.Reader) (string, error) {
data, err := reader.ReadString('\n')
if err != nil {
return "", fmt.Errorf("get input error: %w", err)
}
return strings.ReplaceAll(data, "\n", ""), nil
}
type Person struct {
Name string
Age int
}
func NestedInput(input io.Reader) (*Person, error) {
reader := bufio.NewReader(input)
name, err := getInput(reader)
if err != nil {
return nil, err
}
switch name {
case "q":
return nil, nil
default:
ageStr, err := getInput(reader)
if err != nil {
return nil, err
}
age, err := strconv.Atoi(ageStr)
if err != nil {
return nil, err
}
return &Person{Name: name, Age: age}, nil
}
}
An input of q
returns nil, nil
and could be used to terminate the input, eg if the query was made in a loop. q
的输入返回nil, nil
并可用于终止输入,例如,如果查询是在循环中进行的。
Unit Test单元测试
The unit test单元测试
func Test_nestedInput(t *testing.T)
in a file named input_test.go
should now provide the input data.在名为input_test.go
的文件中,现在应该提供输入数据。
Since the NestedInput
function now expects an io.Reader
as a parameter, we can simply generate the desired input with, for example,由于NestedInput
函数现在需要一个io.Reader
作为参数,我们可以简单地生成所需的输入,例如,
input := strings.NewReader("George\n26\n")
So the test could look something like this:所以测试看起来像这样:
package input
import (
"strings"
"testing"
)
func Test_nestedInput(t *testing.T) {
input := strings.NewReader("George\n26\n")
person, err := NestedInput(input)
if err != nil {
t.Error("nested input failed")
}
if person == nil {
t.Errorf("expected person, but got nil")
return
}
if person.Name != "George" {
t.Errorf("wrong name %s, expected 'George'", person.Name)
}
if person.Age != 26 {
t.Errorf("wrong age %d, expected 26", person.Age)
}
}
Of course, the tests can be extended with further details.当然,可以通过进一步的细节来扩展测试。 But this, as you can see, mocks a nested input.但是,如您所见,这模拟了一个嵌套输入。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.