如何在Go语言中测试嵌套输入

pqwbnv8z  于 2022-12-20  发布在  Go
关注(0)|答案(1)|浏览(135)

我有使用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
}

在我的程序中,我需要有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
}

有可能为这种情况编写单元测试吗?为了测试一个用户输入,我使用了以下代码片段,它工作正常:

var stdin bytes.Buffer
    stdin.Write([]byte(fmt.Sprintf("%s\n", tt.input)))
    GetInput(stdin)

但它不能处理2个嵌套输入

py49o6xq

py49o6xq1#

也许可以考虑使用一个返回特定类型结果的函数,并将其放入单独的包中。
因为我看到提到了nameage,也许我们可以假设一个像Person这样的具体类型来进行说明。
需要注意的是,我们希望包含实际的reader作为参数,而不是硬编码引用os.Stdin,这使得模拟嵌套输入成为可能。
这样,方法的签名可能类似于以下内容:

func NestedInput(input io.Reader) (*Person, error)

对应的类型可以是:

type Person struct {
    Name string
    Age  int
}

如果现在将代码片段合并为一个完整的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
    }
}

q的输入返回nil, nil,并且可以用于终止输入,例如,如果查询是在循环中进行的。

单元测试

单元测试

func Test_nestedInput(t *testing.T)

在名为input_test.go的文件中,现在应该提供输入数据。
由于NestedInput函数现在需要一个io.Reader作为参数,我们可以简单地生成所需的输入,例如,

input := strings.NewReader("George\n26\n")

所以测试看起来像这样:

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

当然,测试还可以扩展更多的细节,但是正如您所看到的,这模拟了嵌套的输入。

相关问题