I want to write a test for a utility function where I use bufio.NewScanner
and Scan()
. I usually use it on stdout
and now I want to simulate a short piece of stream where I can return some static string for the purpose of the test.
bufio.NewScanner(r io.Reader)
takes a Reader
but that only requires a read
method. By reading the source code I couldn't figure out from which buffer it reads or how that gets passed in.
How can I mock that in a short and concise way?
To simply test your code you can use @Sven's answer.
To get an idea of a simple io.Reader
for testing, consider below example:
type R struct {
Data string
done bool
}
func (r *R) Read(p []byte) (n int, err error) {
copy(p, []byte(r.Data))
if r.done {
return 0, io.EOF
}
r.done = true
return len([]byte(r.Data)), nil
}
R
is a custom test type that's implementing an io.Reader
interface by having a Read
method. Thus, it will be accepted by NewScanner
. It can be used as:
func NewR(data string) *R {
return &R{data, false}
}
r := NewR("Test
message
")
scanner := bufio.NewScanner(r)
for scanner.Scan() {
fmt.Printf("Line: %s
", scanner.Text())
}
Output:
Line: Test
Line: message
Both the type R
and its Read
method have been defined to work as a simple source of bytes. Scan
calls its reader's (input to NewScanner
) Read
method until it gets an EOF
or an error. For simplicity, R
's Read
method copies its data to caller's buffer (p
) in its first call and returns an EOF
for any subsequent calls.
Note that actual splitting of the lines at is done by
scanner.Scan
and not r.Read
.
You can modify the Read
method above to get custom behavior as per your requirements.
Working example: https://play.golang.org/p/zqDoQDIE93
You can use bytes.Buffer
since it implements the io.Reader
functions.
Example https://play.golang.org/p/gjjMmT3SzD:
package main
import (
"bufio"
"bytes"
"fmt"
)
func main() {
buf := bytes.NewBufferString("foo
bar")
scanner := bufio.NewScanner(buf)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}