bonzofenix
bonzofenix

Reputation: 645

Testing Stdout with go and ginkgo

here I am making my first steps in go trying to do BDD on a go command line app. I am using Ginkgo, which wraps testing.go and lets you do more expressive BDD. https://github.com/onsi/ginkgo

I am having issues in reading the stdout to do an assertion on it.

Found that on pkg/testing example do stub the output before running but I can not find the way to read that output: http://golang.org/src/pkg/testing/example.go

This is what I would like to do:

cli.go

 package cli
  
 import "fmt"
  
 func Run() {
        fmt.Println("Running cli")
 }

cli_test.go

package cli_test

import (
        . "github.com/altoros/bosh_deployer_cli/lib/cli"

        . "github.com/onsi/ginkgo"
        . "github.com/onsi/gomega"
)

var _ = Describe("Cli", func() {
        It("should parse update stemcell flag", func() {
                Run()
                Expect(stdout).To(Equal("running cli"))
        })
})

Upvotes: 7

Views: 7297

Answers (2)

Onsi Fakhouri
Onsi Fakhouri

Reputation: 71

This is a classic usecase for dependency injection. You can use a gbytes.Buffer from Gomega and have something like this for a unit test:

var _ = Describe("Cli", func() {
        It("should parse update stemcell flag", func() {
                buffer := gbytes.NewBuffer()
                Run(buffer)
                Expect(buffer).To(gbytes.Say("Running cli\n"))
        })
})

Unless you're integration testing the cli, which case I'd recommend using gexec to gexec.Build the binary and then run gexec.Start the command, the resulting gexec.Session object will capture stdout and make it available as a gbytes.Buffer allowing you, again, to write:

Expect(session).To(gbytes.Say("Running cli\n")

More details on gbytes and gexec here:

http://onsi.github.io/gomega/#gbytes-testing-streaming-buffers

http://onsi.github.io/gomega/#gexec-testing-external-processes

Upvotes: 4

creack
creack

Reputation: 121442

Testing Stdout can be tricky. You have multiple choice.

You can override os.Stdout during your test: (think to check the errors)

var _ = Describe("Cli", func() {
        It("should parse update stemcell flag", func() {
                r, w, _ := os.Pipe()
                tmp := os.Stdout
                defer func() {
                        os.Stdout = tmp
                }()
                os.Stdout = w
                go func() {
                        Run()
                        w.Close()
                }()
                stdout, _ := ioutil.ReadAll(r)
                Expect(string(stdout)).To(Equal("Running cli\n"))
        })
})

or you can pass a writer to your function:

cli.go

package cli

import (
        "fmt"
        "io"
)

func Run(w io.Writer) {
        fmt.Fprintln(w, "Running cli")
}

cli_test.go

package cli_test

import (
        . "cli"
        "io"
        "io/ioutil"

        . "github.com/onsi/ginkgo"
        . "github.com/onsi/gomega"
)

var _ = Describe("Cli", func() {
        It("should parse update stemcell flag", func() {
                r, w := io.Pipe()
                go func() {
                        Run(w)
                        w.Close()
                }()
                stdout, _ := ioutil.ReadAll(r)
                Expect(string(stdout)).To(Equal("Running cli\n"))
        })
})

main.go

package main

import (
        "cli"
        "os"
)

func main() {
        cli.Run(os.Stdout)
}

Upvotes: 8

Related Questions