How do I fill os.Stdin in my test for a function that reads from it using a scanner?
I request a user command line input via a scanner using following function:
func userInput() error {
scanner := bufio.NewScanner(os.Stdin)
println("What is your name?")
scanner.Scan()
username = scanner.Text()
/* ... */
}
Now how do I test this case and simulate a user input? Following example does not work. Stdin is still empty.
func TestUserInput(t *testing.T) {
var file *os.File
file.Write([]byte("Tom"))
os.Stdin = file
err := userInput()
/* ... */
}
Mocking
os.Stdin
You're on the right track that
os.Stdin
is a variable (of type*os.File
) which you can modify, you can assign a new value to it in tests.Simplest is to create a temporary file with the content you want to simulate as the input on
os.Stdin
. To create a temp file, useioutil.TempFile()
. Then write the content into it, and seek back to the beginning of the file. Now you can set it asos.Stdin
and perform your tests. Don't forget to cleanup the temp file.I modified your
userInput()
to this:And this is how you can test it:
Running the test, we see an output:
Also see related question about mocking the file system: Example code for testing the filesystem in Golang
The easy, preferred way
Also note that you can refactor
userInput()
to not read fromos.Stdin
, but instead it could receive anio.Reader
to read from. This would make it more robust and a lot easier to test.In your app you can simply pass
os.Stdin
to it, and in tests you can pass anyio.Reader
to it created / prepared in the tests, e.g. usingstrings.NewReader()
,bytes.NewBuffer()
orbytes.NewBufferString()
.