I recently learned you can do this in go:
type Env struct{}
func (e *Env) httpHandler(w http.ResponseWriter, r *http.Request) {
//...
}
func main() {
// ...
e := &Env{}
router := mux.NewRouter()
router.HandleFunc("/foo", e.httpHandler)
}
This is great for dependency injection since when I unit test I can simply call httpHandler
with a mock env.
However, my question is... say you have:
method := e.httpHandler
Is there any way to dynamically change the value of the receiver e
after e.httpHandler
has already been stored into method
with reflection or something? I can change the parameters passed into method()
but it seems like the receiver value is locked in and the only way to change the receiver would be to do e2.httpHandler
. This isn't possible in my case because I'm extracting e.httpHandler
from the mux router and I just want to swap out e
with a different receiver before calling httpHandler
.
For more context I'm using router.Walk()
to essentially do table driven tests where I iterate through every route, call the handler, check that the returned response is the correct shape, etc. However, some routes need slightly different database mocks than others and so it's not ideal to use a one-size-fits-all mock receiver for all routes in the router. I wanted to dynamically swap out the handler receiver with custom mock environments for select handlers.
That's my idea. What do you think?
type Env struct{
db string // should be database, just example
}
func (e *Env) httpHandler(w http.ResponseWriter, r * http.Request) {
}
// In case, create different router by different database.
func newRouter(db string) *mux.Router {
e := &Env{
db:db,
}
router := mux.NewRouter()
router.HandleFunc("/foo", e.httpHandler)
router.HandleFunc("/bar", e.httpHandler)
return router
}
func TestByDatabaseA(t *testing.T) {
r := newRouter("foo")
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
tpl, _ := route.GetPathTemplate()
if !strings.HasPrefix(tpl,"/foo"){
return nil
}
// run test
return nil
})
}
func TestByDatabaseB(t *testing.T) {
r := newRouter("bar")
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
tpl, _ := route.GetPathTemplate()
if !strings.HasPrefix(tpl,"/bar"){
return nil
}
// run test
return nil
})
}