Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Added documentation for how to test path variables #342

Closed
wants to merge 1 commit into from

Conversation

palsivertsen
Copy link

No description provided.

Copy link
Contributor

@elithrar elithrar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using mux.SetURLVars is an alternative to using route variables or table-driven testing. The benefits to the latter is that it’s much clearer, and you can build your tests from actual routes. SetURLVars can be a little magic. In this case, there’s not even a route variable in the URL itself, which makes setting an “invisible” variable odd.

Don’t change the existing example, just amend a smaller example to the bottom of it as an alternative.

@palsivertsen
Copy link
Author

I'm not sure I follow. Yes, the example do show how to use table-driven testing, but it does not show nor test route variables as far as I can see.

In the current example there is a main function:

// endpoints.go
func main() {
    r := mux.NewRouter()
    // A route with a route variable:
    r.HandleFunc("/metrics/{type}", MetricsHandler)

    log.Fatal(http.ListenAndServe("localhost:8080", r))
}

This shows how to use the MetricsHandler but the not source code. Since MetricsHandler is what we actually want to test, the source should be included as well. I'm guessing it would look something like this:

func MetricsHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	typeVar, found := vars["type"]
	if !found {
		// This should never happen as the Gorilla Mux should set it for us
		panic("The request is missing path variable 'type'")
	}
	switch typeVar {
	case "goroutines", "heap", "counters", "queries":
		w.WriteHeader(http.StatusOK)
	default:
		w.WriteHeader(http.StatusNotFound)
	}
}

If you then to run the example, you'll discover it does not compile and has a bug when checking the response so I made a few adjustments:

package examples

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
)

// endpoints_test.go
func TestMetricsHandler(t *testing.T) {
	tt := []struct {
		routeVariable string
		shouldPass    bool
	}{
		{"goroutines", true},
		{"heap", true},
		{"counters", true},
		{"queries", true},
		{"adhadaeqm3k", false},
	}

- 	for _, t := tt {
-		path := fmt.Sprintf("/metrics/%s", t.routeVariable)
+	for _, data := range tt {
+		path := fmt.Sprintf("/metrics/%s", data.routeVariable)
		req, err := http.NewRequest("GET", path, nil)
		if err != nil {
			t.Fatal(err)
		}

		rr := httptest.NewRecorder()
		handler := http.HandlerFunc(MetricsHandler)
		handler.ServeHTTP(rr, req)

		// In this case, our MetricsHandler returns a non-200 response
		// for a route variable it doesn't know about.
-               if rr.Code == http.StatusOK && !t.shouldPass {
+		if (rr.Code == http.StatusOK) != data.shouldPass {
			t.Errorf("handler should have failed on routeVariable %s: got %v want %v",
-				t.routeVariable, rr.Code, http.StatusOK)
+				data.routeVariable, rr.Code, http.StatusOK)
		}
	}
}

If you then try running the test you'll see that MetricsHandler complains that it can not find the type path variable.

What I then did was:

  • Removed table-driven part of test for simplicity. Although it is an excellent way to write tests, it has nothing to with path variables.
  • Add the source of what is actually being tested. MetricsHandler was reanmed to VarLogger to make it more clear what is does.
  • Fixed syntax errors in test example
  • Fixed bug in test example

Alternatively I could add the VarLogger handler to a mux.Router and test this using mux.Router.ServeHTTP but I feel it's out of scope for the example and unit test.

@elithrar
Copy link
Contributor

elithrar commented Jan 27, 2018 via email

@palsivertsen
Copy link
Author

I think we are on the same page regarding beginner friendliness :)

But I think I'm missing something. Please correct me if I'm wrong:
When the readme mentions variables it's referring to path variables. mux.Vars is how you retrieve variables from a request. There are two ways of setting a path variable, add a new route with /path/{myVar} path syntax or use mux.SetURLVars.

I don't see how the current example illustrates how to use path variables when it does not include any of mux.Vars, /path/{myVar} or mux.SetURLVars?

@stale
Copy link

stale bot commented Dec 9, 2018

This issue has been automatically marked as stale because it hasn't seen a recent update. It'll be automatically closed in a few days.

@stale stale bot added the stale label Dec 9, 2018
@stale stale bot closed this Dec 17, 2018
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants