key := "black"
e := `"` + key + `"`
w.Header().Set("Etag", e)
w.Header().Set("Cache-Control", "max-age=2592000") // 30 days
writeImage is a function that writes an image into a http.ResponseWriter (to read more about this go to my previous post Playing with
images in HTTP response in golang (http://www.sanarias.com/blog/1214PlayingwithimagesinHTTPresponseingolang)).
This is great because you can use the recorder as any http.ResponseWriter and also use it to check the response that comes from the
handler. In this case, we can check that the HTTP response code is equal to http.StatusOK
package main
import (
"net/http"
"net/http/httptest"
"testing"
)
blackHandlerFunc := http.HandlerFunc(blackHandler)
if r, err := http.NewRequest("GET", "", nil); err != nil {
t.Errorf("%v", err)
} else {
recorder := httptest.NewRecorder()
blackHandlerFunc.ServeHTTP(recorder, r)
if recorder.Code != http.StatusOK {
t.Errorf("returned %v. Expected %v.", recorder.Code, http.StatusOK)
}
}
}
$ go test
PASS
ok local/cache 0.011s
Test coverage:
Now lets measure our test coverage for this test. Go comes with a tool called cover and a great article (http://blog.golang.org/cover) that
explains all you need to know about it.
$ go test -cover
PASS
coverage: 57.7% of statements
ok local/cache 0.012s
We know we are not covering the main() function. This might explain why we have a lower percentage of coverage. Lets see what our test
really covers:
go test -coverprofile=coverage.out
go tool cover -html=coverage.out
We need to improve our test so that the cache code is also covered.
This can easily be done with the ResponseRecorder (http://golang.org/pkg/net/http/httptest/#ResponseRecorder) type from the httptest
(http://golang.org/pkg/net/http/httptest/) package, since the ResponseRecorder is an implementation of the http.ResponseWriter
(http://golang.org/pkg/net/http/#ResponseWriter). So you can read information from it like you would do with a http.ResponseWriter type.
We then use the Etag when building our second request by setting it in the If-None-Match in the http.Header .
The last thing to do is to check this time that the response.Code is equal to http.StatusNotModified .
import (
"net/http"
"net/http/httptest"
"testing"
)
blackHandlerFunc := http.HandlerFunc(blackHandler)
var etag string
// first request
if r, err := http.NewRequest("GET", "", nil); err != nil {
t.Errorf("%v", err)
} else {
recorder := httptest.NewRecorder()
blackHandlerFunc.ServeHTTP(recorder, r)
if recorder.Code != http.StatusOK {
t.Errorf("returned %v. Expected %v.", recorder.Code, http.StatusOK)
}
// record etag to test cache
etag = recorder.Header().Get("Etag")
}
// test caching
if r, err := http.NewRequest("GET", "", nil); err != nil {
t.Errorf("%v", err)
} else {
r.Header.Set("If-None-Match", etag)
recorder := httptest.NewRecorder()
blackHandlerFunc.ServeHTTP(recorder, r)
if recorder.Code != http.StatusNotModified {
t.Errorf("returned %v. Expected %v.", recorder.Code, http.StatusNotModified)
}
}
}
$ go test -cover
PASS
coverage: 69.2% of statements
ok local/cache 0.010s
go test -coverprofile=coverage.out
go tool cover -html=coverage.out
That looks nice! :) As I said before, the reason why we do not get 100% coverage is because there is no test covering main() and error
handling code in writeImage() . But the important part was to properly test the blackHander function.
I hope you found this post useful and that this will help you build proper tests for your applications.
Here are some resources that helped me come up with this article:
Santiaago
(/blog/215TestingHTTPcachinginGo#disqus_thread)
0 Comments sanarias
1 gna
Sort by Best
Recommend Share
ALSO ON SANARIAS
Santiago Arias: Playing with images in HTTP response in Santiago Arias: Order dates chronologically in Go
2 comments 3 years ago
2 comments 2 years ago Humberto Henrique Nice, but seems to have a small bug ?
santiaago I am glad you nd it useful :)By the way this is the return a[i].Date.Before(a[j]) should be
avatar generator I built: