smartystreets / goconvey

Go testing in the browser. Integrates with `go test`. Write behavioral tests in Go.
http://smartystreets.github.io/goconvey/
Other
8.23k stars 554 forks source link

Running a function inside a goconvey context #658

Open ezk84 opened 2 years ago

ezk84 commented 2 years ago

I've recently come across an issue when testing using httptest, and this answer gives a great solution.

To summarise, when a httptest handler runs in the server's own goroutine, that code doesn't run inside a goconvey context, so any calls from that handler to So, Convey, etc end up in a pretty nasty-looking error.

var fakeAction func()
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
     // some random stuff with w and r, but then crucially
     fakeAction()
}))

// ...
Convey("something", func() {
      fakeAction = func() {
          // stuff producing err
          So(err, ShouldBeNill) // will cause error: So is called without goconvey context
      }

      http.Get(ts.URL)
})

The solution is to make the enclosing Convey handler pass the convey context explicitly like so:

Convey("something", func(c C) {
    fakeAction = func() {
        // stuff
        c.So(err, ShouldBeNill) // good
    }

    http.Get(ts.URL)
})

The problem occurs when one has built up a bunch of testing utilities that call So, that one wants to call from fakeAction. We'd now need to modify all of these to take a goconvey context. This could be made more convenient by having that c C provide something like a Run(f func()) function that allows all calls to goconvey functions inside f to have the right context.

Then we could have

Convey("something", func(c C) {
    fakeAction = func() {
        // stuff
        c.Run(func() { 
            UtilityThatCallsSo()
        })
    }

    http.Get(ts.URL)
})