Melanjutkan dari modul sebelumnya, jika kita jalankan test, dapat dilihat terdapat error.
panic: runtime error: invalid memory address or nil pointer dereference
-> github.com/alexedwards/scs/v2.(*SessionManager).LoadAndSave.func1
...
... truncated error message
...
--- FAIL: Test_application_handlers (0.02s)
handlers_test.go:39: for home: expected status 200, but got 500
handlers_test.go:39: for 404: expected status 404, but got 500
FAIL
FAIL webapp/cmd/web 0.762s
FAIL
Hal ini terjadi karena pada aplikasi sudah ditambahkan session, sementara pada modul test belum ditambahkan session.
Untuk memperbaikinya, buka file cmd/web/setup_test.go, lalu tambahkan session
package main
import (
"os"
"testing"
)
var app application
func TestMain(m *testing.M) {
app.Session = getSession() //tambahkan session pada modul test
os.Exit(m.Run())
}
Jika kita jalankan kembali test, error sudah tidak ada. (perintah dibawah dijalankan pada directory cmd/web).
$ go test .
ok webapp/cmd/web 1.096s
Membuat Test untuk Session
Pada halaman home page tidak hanya sekedar konten statis, namun terdapat session. Kita dapat membuat fungsi test untuk session.
Buka file cmd/web/handlers_test.go, lalu tambahkan fungsi TestAppsHome dan fungsi helper addCtxSessToReq.
package main
import (
"context"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func Test_application_handlers(t *testing.T) {
var theTests = []struct {
name string
url string
expectedStatusCode int
}{
{"home", "/", http.StatusOK},
{"404", "/qwerty", http.StatusNotFound},
}
//menggunakan environment variable
//var app application
routes := app.routes()
//create a test server
ts := httptest.NewTLSServer(routes)
defer ts.Close()
templatePath = "./../../templates/"
//testing
for _, e := range theTests {
resp, err := ts.Client().Get(ts.URL + e.url)
if err != nil {
t.Log(err)
t.Fatal(err)
}
if resp.StatusCode != e.expectedStatusCode {
t.Errorf("for %s: expected status %d, but got %d", e.name, e.expectedStatusCode, resp.StatusCode)
}
}
}
func TestAppsHome(t *testing.T) {
//create request
req, _ := http.NewRequest("GET", "/", nil)
req = addCtxSessToReq(req, app)
rr := httptest.NewRecorder()
handler := http.HandlerFunc(app.Home)
handler.ServeHTTP(rr, req)
//check status code
if rr.Code != http.StatusOK {
t.Errorf("TestAppHome: returned wrong status code, expected 200 but got %d", rr.Code)
}
//check html content by comparing wiht static text that we wrote on home.page.gohtml
body, _ := io.ReadAll(rr.Body)
if !strings.Contains(string(body), `<small>Session:`) {
t.Error("did not find correct text in html")
}
}
func addCtxSessToReq(req *http.Request, app application) *http.Request {
req = req.WithContext(context.WithValue(req.Context(), contextUserKey, "unknown"))
ctx, _ := app.Session.Load(req.Context(), req.Header.Get("X-Session"))
return req.WithContext(ctx)
}
Sekarang session sudah ditambahkan kedalam request, jika kita jalankan test (test dijalankan dalam directory cmd/web).
$ go test .
ok webapp/cmd/web 1.096s
PS F:\Project\gotest\webapp\cmd\web> go test -v .
=== RUN TestForm_Has
--- PASS: TestForm_Has (0.00s)
=== RUN TestForm_Required
--- PASS: TestForm_Required (0.00s)
=== RUN TestForm_Check
--- PASS: TestForm_Check (0.00s)
=== RUN TestForm_ErrorGet
--- PASS: TestForm_ErrorGet (0.00s)
=== RUN Test_application_handlers
--- PASS: Test_application_handlers (0.08s)
=== RUN TestAppsHome
--- PASS: TestAppsHome (0.00s)
=== RUN Test_application_addIPToContext
middleware_test.go:40: 192.0.2.1
middleware_test.go:40: unknown
middleware_test.go:40: 192.163.1.3
middleware_test.go:40: hello
--- PASS: Test_application_addIPToContext (0.00s)
=== RUN Test_application_ipFromContext
--- PASS: Test_application_ipFromContext (0.00s)
=== RUN Test_application_routes
--- PASS: Test_application_routes (0.00s)
PASS
ok webapp/cmd/web 1.037s
Latihan
Sampai disini kita sudah mempelajari bagaimana melakukan test untuk individual handler dan menggunakan session. Untuk latihan, coba modifikasi fungsi TestAppHome menggunakan table test.
Solusi
func TestAppHome(t *testing.T) {
var tests = []struct {
name string
putInSession string
expctedHTML string
}{
{"First Visit", "", "<small>Session:"},
{"Second Visit", "skillplus", "<small>Session: skillplus"},
}
for _, e := range tests {
req, _ := http.NewRequest("GET", "/", nil)
req = addCtxSessToReq(req, app)
_ = app.Session.Destroy(req.Context())
if e.putInSession != "" {
app.Session.Put(req.Context(), "test", e.putInSession)
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(app.Home)
handler.ServeHTTP(rr, req)
//check status code
if rr.Code != http.StatusOK {
t.Errorf("TestAppHome: returned wrong status code, expected 200 but got %d", rr.Code)
}
body, _ := io.ReadAll(rr.Body)
if !strings.Contains(string(body), e.expctedHTML) {
t.Errorf("%s: did not find %s in response body", e.name, e.expctedHTML)
}
}
}