Writing Go Tests for Stdin Interactions
In software testing, it's often necessary to write tests that interact with stdin, the standard input stream. This is particularly relevant when testing applications that read input from the console or a user interface.
Consider the following Go application that reads lines from stdin and echoes them back to stdout:
<code class="go">package main import ( "bufio" "fmt" "io" "os" ) func main() { reader := bufio.NewReader(os.Stdin) for { fmt.Print("> ") bytes, _, err := reader.ReadLine() if err == io.EOF { os.Exit(0) } fmt.Println(string(bytes)) } }</code>
To test this application, a test case can be written to simulate user input and compare the results to the expected output:
<code class="go">package main import ( "bufio" "io" "os" "os/exec" "testing" ) func TestInput(t *testing.T) { subproc := exec.Command(os.Args[0]) stdin, _ := subproc.StdinPipe() stdout, _ := subproc.StdoutPipe() defer stdin.Close() input := "abc\n" subproc.Start() io.WriteString(stdin, input) reader := bufio.NewReader(stdout) bytes, _, _ := reader.ReadLine() output := string(bytes) if input != output { t.Errorf("Wanted: %v, Got: %v", input, output) } subproc.Wait() }</code>
However, this test may fail with the error: "Wanted: abc, Got: --- FAIL: TestInput (3.32s)".
To resolve this issue, consider the following solution:
Instead of manipulating stdin and stdout directly in the main function, define a separate function that accepts io.Reader and io.Writer as parameters and performs the desired operations. The main function can then call this function, making it easier to test.
For example, create a function called Echo:
<code class="go">func Echo(reader io.Reader, writer io.Writer) { reader := bufio.NewReader(reader) for { fmt.Print("> ", writer) bytes, _, err := reader.ReadLine() if err == io.EOF { return } fmt.Println(string(bytes), writer) } }</code>
In the test, directly call the Echo function instead of interacting with stdin and stdout:
<code class="go">// ... func TestInput(t *testing.T) { inputReader := strings.NewReader("abc\n") outputWriter := new(bytes.Buffer) Echo(inputReader, outputWriter) result := outputWriter.String() if input != result { t.Errorf("Wanted: %v, Got: %v", input, result) } }</code>
This test should now pass, as it directly tests the Echo function without relying on stdin and stdout manipulation.
The above is the detailed content of How to Test Go Applications That Interact with Standard Input (Stdin)?. For more information, please follow other related articles on the PHP Chinese website!