hookenz
hookenz

Reputation: 38879

How do I write a go Test function for something that reads from stdin?

I have go test code similar to this:

func TestRollback(t *testing.T) {

  store := NewStore()
  
  // do some stuff

  err := store.Rollback()
  
  // checks
}

The problem is store.Rollback() has a prompt read from the stdin for y or n

How do I send "y" to the test process when running go test -v --run TestRollback

Upvotes: 2

Views: 763

Answers (2)

jub0bs
jub0bs

Reputation: 66183

The difficulty in testing your Rollback method stems from hardcoding its dependency on singleton os.Stdin. Tinkerer's answer is viable but, because it mutates that package-level variable, it doesn't lend itself to running tests in parallel.

A preferable alternative (IMO) consists in using an interface. Testing often rhymes with interface, in Go. Here, because os.Stdin satisfies the io.Reader interface, you could parameterise your Store type with an io.Reader passed to your factory function:

type Store struct {
  // other fields, omitted here
  in io.Reader
}

func NewStore(in io.Reader) *Store {
  store := Store {
    // other fields, omitted here
    in: in,
  }
  return &store
}

Then, in your test functions, you could use a concrete type that satisfies io.Reader and is easily configurable, such as a *strings.Reader:

func TestRollback(t *testing.T) {
  // arrange
  in := strings.Reader("-- put contents of stdin here --")
  store := NewStore(in)
  // act
  err := store.Rollback()
  // assert
  // ...
}

Upvotes: 2

Tinkerer
Tinkerer

Reputation: 1068

The following can redirect stdin temporarily.

rd,wr,err := os.Pipe()
saved := os.Stdin
os.Stdin = rd

... Test code feeds wr ...

os.Stdin = saved

Upvotes: 1

Related Questions