Official blog of KEINOS but mostly for my own reference. A Japanese made in Mexico with Mexican quality. Who monkey around the jungle of codes. ;-)
「”golang” test “os.Stdin” “keinos”」でググってもヒットしなかったので、自分のググラビリティとして。
os.Stdin during the test in GoIn the dependency injection point of view, it is a good practice to var OsStdin = os.Stdin and use OsStdin instead of os.Stdin. Then monkey patch (temporary replace) the variable during the test.
But if the external package doesn’t support that OsStdin alias feature, and uses os.Stdin, we need to mock the os.Stdin some how.
Here’s my snippet of the helper function to mock the os.Stdin.
// mockStdin is a helper function that lets the test pretend dummyInput as os.Stdin.
// It will return a function for `defer` to clean up after the test.
//
// Note: `ioutil.TempFile` should be replaced to `os.CreateTemp` for Go v1.16 or higher.
func mockStdin(t *testing.T, dummyInput string) (funcDefer func(), err error) {
t.Helper()
oldOsStdin := os.Stdin
tmpfile, err := ioutil.TempFile(t.TempDir(), t.Name())
if err != nil {
return nil, err
}
content := []byte(dummyInput)
if _, err := tmpfile.Write(content); err != nil {
return nil, err
}
if _, err := tmpfile.Seek(0, 0); err != nil {
return nil, err
}
// Set stdin to the temp file
os.Stdin = tmpfile
return func() {
// clean up
os.Stdin = oldOsStdin
os.Remove(tmpfile.Name())
}, nil
}
package main
import (
"bufio"
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// ----------------------------------------------------------------------------
// The Target Function
// ----------------------------------------------------------------------------
// ReadFromSTDIN returns a string read from STDIN. Which you can not edit.
func ReadFromSTDIN() (string, error) {
var stdin []byte
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
stdin = append(stdin, scanner.Bytes()...)
}
if err := scanner.Err(); err != nil {
return "", err
}
return string(stdin), nil
}
// ----------------------------------------------------------------------------
// The Test
// ----------------------------------------------------------------------------
func TestReadFromSTDIN(t *testing.T) {
userInput := "this is my dummy input 123"
funcDefer, err := mockStdin(t, userInput)
if err != nil {
t.Fatal(err)
}
defer funcDefer()
expect := "this is my dummy input 123"
actual, err := ReadFromSTDIN()
require.NoError(t, err)
assert.Equal(t, expect, actual)
}
// ----------------------------------------------------------------------------
// Helper Functions
// ----------------------------------------------------------------------------
// mockStdin is a helper function that lets the test pretend dummyInput as os.Stdin.
// It will return a function to `defer` clean up after the test.
func mockStdin(t *testing.T, dummyInput string) (funcDefer func(), err error) {
t.Helper()
oldOsStdin := os.Stdin
tmpfile, err := ioutil.TempFile(t.TempDir(), t.Name())
if err != nil {
return nil, err
}
content := []byte(dummyInput)
if _, err := tmpfile.Write(content); err != nil {
return nil, err
}
if _, err := tmpfile.Seek(0, 0); err != nil {
return nil, err
}
// Set stdin to the temp file
os.Stdin = tmpfile
return func() {
// clean up
os.Stdin = oldOsStdin
os.Remove(tmpfile.Name())
}, nil
}
| Ref: “Mocking os.Stdin” | Fill os.Stdin for function that reads from it @ StackOverflow |