onsi / ginkgo

A Modern Testing Framework for Go
http://onsi.github.io/ginkgo/
MIT License
8.22k stars 650 forks source link

Issue with the report generation. #1249

Closed yatindrav closed 1 year ago

yatindrav commented 1 year ago

I've written the following code: type TestRun struct { TestCmd string TestParam string } Tests []TestRun

Context("Executing Sanity tests", func() {
    for i := range Tests {
        It("Now Running test " + Tests[i].TestCmd, func() {  //report shows the exact command
            var command *exec.Cmd
            if Tests[i].TestParam != "" {
                command = exec.Command(Tests[i].TestCmd, Tests[i].TestParam)
            } else {
                command = exec.Command(Tests[i].TestCmd)
            }
            session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
            Ω(err).NotTo(HaveOccurred())
            session.Wait()
            Eventually(session).WithTimeout(time.Second * 10).Should(gexec.Exit(0)) //with exit code 0
        })
    }
})

And if run this using the following command: ginkgo --json-report=report.json --output-dir=./log

It saves the output of last command for all the commands in the report. What is wrong in this code? Quick response will help.

yatindrav commented 1 year ago

I believe in the above case all iterations are running the same tests.

onsi commented 1 year ago

hey @yatindrav the issue is that the i variable is captured by the It closure - any changes to i are therefore seen by all closures and you end up with the final i value... so all the iterations end up running the last test. Here's a non-Ginkgo example of this behavior:

names := []string{"Bob", "Jim", "Jane", "Alice"}
callbacks := []func(){}
for i := range names {
    callbacks = append(callbacks, func() {
        fmt.Println(names[i])
    })
}

for _, f := range callbacks {
    f()
}

will print:

Alice
Alice
Alice
Alice

The common way to fix this is:

Context("Executing Sanity tests", func() {
    for i := range Tests {
        i := i // <== this will create a local copy of i that will no longer change between iterations
        It("Now Running test " + Tests[i].TestCmd, func() {  //report shows the exact command
            var command *exec.Cmd
            if Tests[i].TestParam != "" { //Tests[i] will now be correct
                command = exec.Command(Tests[i].TestCmd, Tests[i].TestParam)
            } else {
                command = exec.Command(Tests[i].TestCmd)
            }
            session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
            Ω(err).NotTo(HaveOccurred())
            session.Wait()
            Eventually(session).WithTimeout(time.Second * 10).Should(gexec.Exit(0)) //with exit code 0
        })
    }
})
yatindrav commented 1 year ago

Thanks onsi it worked!

yatindrav commented 1 year ago

Closing it.