Web App Testing – Session

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)
		}
	}
}
Sharing is caring:

Leave a Comment