thoughts from places


Mocking command line flags and stdin in Go

I recently wrote a program where I wanted to mock command line flags and stdin for testing.

Normally to parse flags in Go you call flag.Parse(). If you look at the source code you'll see that it's just a wrapper function around flag.CommandLine.Parse(os.Args[1:]). Where CommandLine is the default flagset created for you. The fact that Parse() here accepts arguments is exactly what I'm looking for. I just need to write my own wrapper function around this and change the slice that gets passed in to Parse().

func setupInputs(args []string) {

    a := os.Args[1:]
    if args != nil {
        a = args
    }

    flag.CommandLine.Parse(a)
}

My program also reads from stdin. To mock this I created a pointer variable of type file. This matches the same type signature as os.Stdin. Then in my program I simply refer to this variable when I want to read or write from stdin.

Here I expand the setupInputs function above to handle setting up stdin.

var stdin *os.File

func setupInputs(args []string, file *os.File) {

    ... // Code from above function removed to make reading clearer

    if file != nil {
        stdin = file
    } else {
        stdin = os.Stdin
    }
}

In my tests I simply create a temporary file, write to it and then pass it into the setup function. Like so:

// Create temporary file
file, _ := ioutil.TempFile(os.TempDir(), "stdin")
defer os.Remove(file.Name())

// Write to it
file.WriteString("content from stdin")

// Pass it in
setupInputs([]string{}, file)

To see examples of using this technique have a look at my tests on github

If you have any thoughts about this and want to contact me send an email to stdin@neillyons.io


Neil Lyons

Freelance Web Developer based in the UK.