Faking mux.Vars

1,453 views
Skip to first unread message

Donovan Hide

unread,
Sep 6, 2012, 11:00:11 AM9/6/12
to goril...@googlegroups.com
Hi,

if I'm testing some code which depends on mux.Vars. I've got this helper method:

func buildRequest(method string, url string, doctype uint32, docid uint32) *http.Request {
req, _ := http.NewRequest(method, url, nil)
req.ParseForm()
vars := make(map[string]string)
vars["doctype"] = string(doctype)
vars["docid"] = string(docid)
context.DefaultContext.Set(req, 0, vars)
return req
}

but running mux.Vars(req) in the code that is being tested returns an empty map[] 

Am I missing something?

Cheers,
Donovan

Donovan Hide

unread,
Sep 6, 2012, 6:05:46 PM9/6/12
to goril...@googlegroups.com
Hi again,

apart from a basic misunderstanding of string constructors (;-)) I worked out that the problem lay with the use of the contextKey alias used as the map key. If I promoted this to exported from the mux package then I could get it to work and mux.Vars returns the correct results.

func buildRequest(method string, url string, doctype uint32, docid uint32) *http.Request {
req, _ := http.NewRequest(method, url, nil)
req.ParseForm()
var vars = map[string]string{
"doctype": strconv.FormatUint(uint64(doctype), 10),
"docid":   strconv.FormatUint(uint64(docid), 10),
}
context.DefaultContext.Set(req, mux.ContextKey(0), vars) // mux.ContextKey exported
return req
}

I know this is a bit of a hack for testing purposes, but it would be great if mux.Vars was more easily mocked/faked without altering the gorilla source code. Not sure what the best way to do this would be though.

Cheers,
Donovan.

ab

unread,
Jan 17, 2013, 1:56:31 PM1/17/13
to goril...@googlegroups.com
Hi Donovan,

We are having the very same problem to write some UT.

It seems to me that your hack is the only solution.

The "correct" way to set the mux.Vars is to use mux.setVars(), called only by router.serveHTTP().
And serveHTTP() has a defer context.Clear(req) that clears the mux.Vars from the context.

The second option is to call context.Set with the appropriate parameters. And the key has to be a contextKey which is just an int.

My hack is closed to yours but avoid exporting the type from mux, I simply remove it and declare varsKey as an int. It works too.

But I agree, it is a real problem for writing proper UT.

ab

unread,
Jan 17, 2013, 2:00:55 PM1/17/13
to goril...@googlegroups.com
Hi again,


My hack is closed to yours but avoid exporting the type from mux, I simply remove it and declare varsKey as an int. It works too.

Just a though, it is not a very good idea because you could overwrite the vars or the route using context.Set(r, 0, vars) within a handler. Your option is better because it is more explicit.

Cheers,
Anthony

Donovan Hide

unread,
Jan 17, 2013, 2:55:52 PM1/17/13
to goril...@googlegroups.com
Hi Anthony,

It's quite a major API change, but altering the Mux type to:

type Mux interface{
Add(key, value string)
Del(key string)
Get(key string) string
Set(key, value string)
}

would allow the mocking out of the request variables. I think the main problem is the use of the builtin type map as the dictionary. It's been a while since I looked at the Gorilla source, but this does seem logical to me...

Cheers,
Donovan.


--
 
 

ab

unread,
Jan 18, 2013, 7:44:41 AM1/18/13
to goril...@googlegroups.com
Hi Donovan,

The only way I have found right now to write some UT is something like that :

    w := httptest.NewRecorder()
    u, err := mux.Router.Get("web_boutiqueadminsettings").URL("name", name)
    if err != nil {
        t.Fatal(err.Error())
    }
    r, _ := http.NewRequest("GET", u.String(), nil)

    mux.Router.ServeHTTP(w, r)


And then check the content of w.Body or check the results in the db or anything that the request should have modified.

Cheers,
Anthony

Rodrigo Moraes

unread,
Jan 23, 2013, 6:18:15 AM1/23/13
to Gorilla web toolkit
Hi,
Currently mux misses a mocking mechanism for the variables -- you have
to create your own ServeHttp() to capture them.

It gets more complicated with subrouters (Hi, Surma!). I want to
address this at some point.

-- rodrigo

matt n

unread,
Sep 10, 2013, 9:14:54 PM9/10/13
to goril...@googlegroups.com
Any movement on this?  I'm trying to write unit tests for my handlers, but the inability to inject Vars is a bit of a problem.

Since they are unit tests, I don't really need any kind of cleanup or what not.

ps

unread,
Oct 3, 2013, 12:30:14 AM10/3/13
to goril...@googlegroups.com
Hello,

I have a test failing because Vars is an empty map, as described above. I'm generating an HTTP request, such as: http.NewRequest("GET", "http://localhost:3000/employees/1", nil).

However the id (1) variable isn't being captured. That's what we're talking about here, right?

I'm confused, because isn't this a legitimate request like any other (from a browser, curl, etc.)?

ps

unread,
Oct 3, 2013, 10:27:08 PM10/3/13
to goril...@googlegroups.com
I've been looking to inject the vars as suggested in the top post here, but it appears that context.DefaultContext is no longer available.

(I don't even see it in the history of the four commits of context.go on the GitHub-hosted project--that must have been an old remnant from Google Code-hosting days?)

I think I'll need to add another layer of indirection to construct the request...

Kamil Kisiel

unread,
Oct 4, 2013, 9:50:17 PM10/4/13
to goril...@googlegroups.com
See my reply on golang-nuts for one possible way to do this:

ps

unread,
Oct 5, 2013, 11:04:21 AM10/5/13
to goril...@googlegroups.com
Yup, got it and replied there. It's working great--thanks!

Now I just need to clean up my code! (My handlers already have their own package, I need to move the vars injector out of main and into the top-level there.)
Message has been deleted

Błażej Krzakala

unread,
Jun 30, 2020, 5:59:50 AM6/30/20
to Gorilla web toolkit
t.Run("By request in content add", func(t *testing.T) {
param1 := 300
param2 := 1058
muxVars := map[string]string{
"param1": strconv.FormatUint(uint64(param1), 10),
"param2": strconv.FormatUint(uint64(param2), 10),
}
requestToTest, err := http.NewRequest("POST", "/doesnt-matter", nil)
assert.Nil(t, err)
requestToTest = mux.SetURLVars(requestToTest, muxVars)
props := mux.Vars(requestToTest)
assert.Equal(t, props["param1"], param1) assert.Equal(t, props["param2"], param2)
})
Reply all
Reply to author
Forward
0 new messages