如何为从 stdin 读取的内容编写 go Test 函数?

How do I write a go Test function for something that reads from stdin?

我有类似这样的测试代码:

func TestRollback(t *testing.T) {

  store := NewStore()
  
  // do some stuff

  err := store.Rollback()
  
  // checks
}

问题是 store.Rollback() 提示从标准输入读取 y 或 n

当 运行 go test -v --run TestRollback

时如何将“y”发送到测试进程

以下可以暂时重定向stdin。

rd,wr,err := os.Pipe()
saved := os.Stdin
os.Stdin = rd

... Test code feeds wr ...

os.Stdin = saved

测试您的 Rollback 方法的困难在于硬编码它对单例的依赖性 os.Stdin 是可行的,但是因为它改变了包级变量,所以它不适合并行进行 运行 测试。

一个更好的选择(IMO)在于使用一个接口。在 Go 中,测试通常与接口押韵。在这里,因为 os.Stdin 满足 io.Reader 接口,您可以使用传递给工厂函数的 io.Reader 参数化 Store 类型:

type Store struct {
  // other fields, omitted here
  in io.Reader
}

func NewStore(in io.Reader) *Store {
  store := Store {
    // other fields, omitted here
    in: in,
  }
  return &store
}

然后,在您的测试函数中,您可以使用满足 io.Reader 且易于配置的具体类型,例如 *strings.Reader:

func TestRollback(t *testing.T) {
  // arrange
  in := strings.Reader("-- put contents of stdin here --")
  store := NewStore(in)
  // act
  err := store.Rollback()
  // assert
  // ...
}