英文:
How do I write a go Test function for something that reads from stdin?
问题
我有一个类似于这样的go测试代码:
func TestRollback(t *testing.T) {
store := NewStore()
// 做一些操作
err := store.Rollback()
// 检查
}
问题是store.Rollback()
会从标准输入(stdin)读取一个提示,要求输入"y"或"n"。
当运行go test -v --run TestRollback
时,如何向测试进程发送"y"呢?
英文:
I have go test code similar to this:
func TestRollback(t *testing.T) {
store := NewStore()
// do some stuff
err := store.Rollback()
// checks
}
The problem is store.Rollback() has a prompt read from the stdin for y or n
How do I send "y" to the test process when running go test -v --run TestRollback
答案1
得分: 2
你的Rollback
方法测试的困难在于它在单例os.Stdin
上硬编码了依赖关系。
Tinkerer的答案是可行的,但是因为它改变了那个包级变量,所以不适合并行运行测试。
一个更可取的替代方案(在我看来)是使用接口。在Go语言中,测试通常与接口相关。在这里,因为os.Stdin
满足io.Reader
接口,你可以在工厂函数中将io.Reader
作为参数传递给你的Store
类型:
type Store struct {
// 其他字段,在此省略
in io.Reader
}
func NewStore(in io.Reader) *Store {
store := Store {
// 其他字段,在此省略
in: in,
}
return &store
}
然后,在你的测试函数中,你可以使用满足io.Reader
接口且易于配置的具体类型,比如*strings.Reader
:
func TestRollback(t *testing.T) {
// 准备
in := strings.NewReader("-- 在这里放入stdin的内容 --")
store := NewStore(in)
// 执行
err := store.Rollback()
// 断言
// ...
}
英文:
The difficulty in testing your Rollback
method stems from hardcoding its dependency on singleton os.Stdin
.
Tinkerer's answer is viable but, because it mutates that package-level variable, it doesn't lend itself to running tests in parallel.
A preferable alternative (IMO) consists in using an interface. Testing often rhymes with interface, in Go. Here, because os.Stdin
satisfies the io.Reader
interface, you could parameterise your Store
type with an io.Reader
passed to your factory function:
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
}
Then, in your test functions, you could use a concrete type that satisfies io.Reader
and is easily configurable, such as a *strings.Reader
:
func TestRollback(t *testing.T) {
// arrange
in := strings.Reader("-- put contents of stdin here --")
store := NewStore(in)
// act
err := store.Rollback()
// assert
// ...
}
答案2
得分: 1
以下可以临时重定向标准输入。
rd, wr, err := os.Pipe()
saved := os.Stdin
os.Stdin = rd
... 测试代码将数据写入 wr ...
os.Stdin = saved
英文:
The following can redirect stdin temporarily.
rd,wr,err := os.Pipe()
saved := os.Stdin
os.Stdin = rd
... Test code feeds wr ...
os.Stdin = saved
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论