Reputation: 75
Using Go 1.11 I have a function that prints a label above a user input. This is fine and works but when I have started to write the test for this function it prints out this label when running the tests.
I have also use log.Print
but then in the test file adding the following
func init() {
log.SetOutput(ioutil.Discard)
}
This stops the log.Print
from being displayed when running the tests. So how do I get it to do the same for any fmt.Println
?
UPDATE
I thought I would post the func that I am testing and how I set up,
func checkLoop(loopCount int) int {
var input int
var ok bool
for !ok {
fmt.Printf("Input %d :: ", loopCount)
ok, input = takeInput()
}
return input
}
So takeInput()
only takes the users input, using fmt.Scan
and checks it to see if its within a set range I want. So it returns a bool and if its false it will re-use the label to check what input number it is.
Upvotes: 5
Views: 1871
Reputation: 166855
For example,
discard_test.go
:
package main
import (
"fmt"
"os"
"syscall"
"testing"
)
func printLabel(label string) {
fmt.Println(label)
}
func TestDiscardLabel(t *testing.T) {
defer func(stdout *os.File) {
os.Stdout = stdout
}(os.Stdout)
os.Stdout = os.NewFile(uintptr(syscall.Stdin), os.DevNull)
printLabel("Discard:")
}
func TestPrintLabel(t *testing.T) {
printLabel("Print:")
}
Output:
$ go test discard_test.go -v
--- PASS: TestDiscardLabel (0.00s)
=== RUN TestPrintLabel
Print:
--- PASS: TestPrintLabel (0.00s)
PASS
$
Upvotes: 3
Reputation: 39430
fmt.Printf
use the os.Stdout
so you can simply:
os.Stdout = nil
fmt.Println("Hello Gopher!")
or more elegant:
os.Stdout,_ = os.Open(os.DevNull)
fmt.Println("Hello Gopher!")
Hope this help
Upvotes: 1
Reputation: 55563
Either you're testing on a wrong level or you're testing a wrong thing, let me explain.
If it's for some reason valuable for you to test that your function prints something and also accepts user input, then go ahead and do end-to-end testing for it—that is, also test that it prints what it's expected to print, and once it does that, submit it some canned input and then verify it processes it the way you expect it to.
I don't know your code but supposedly you should stop
using fmt.P*
family of functions—which imply using os.Std{in|out|err}
and write the functions forming the core of your code accepting io.Reader
and io.Writer
interfaces and
call them from the top-level code passing them os.Stdin
and os.Stderr
etc.
Then, when testing, it will be easy to pass these functions stub (or mock) values which also satisfy the said interfaces.
(The fmt
package supports formatted printing using the fmt.FP*
family of functions, where that F
is a historical artefact meaning "file" and allows you to pass it any value implementing io.Writer
.)
Another possibility is that what you explained looks like a code smell: a function concerned with processing some input data has no business printing any labels anywhere.
So it well may be that you instead should split your function at least in two: the "outer" one prompts the user and reads the data, and the second accepts the data and processes it. You then test the second one.
Upvotes: 3