Testing Login and Logout Functionalities
Based on the requirements for this functionality, this code should allow the use of a valid username/password combination and disallow the use of an invalid username/password combination.
To test the isUserValid function in models.user.go, let's update the models.user_test.go with the following test:
// models.user_test.go
func TestUserValidity(t *testing.T) {
if !isUserValid("user1", "pass1") {
t.Fail()
}
if isUserValid("user2", "pass1") {
t.Fail()
}
if isUserValid("user1", "") {
t.Fail()
}
if isUserValid("", "pass1") {
t.Fail()
}
if isUserValid("User1", "pass1") {
t.Fail()
}
}
This test uses several username/password combinations to test that the isUserValid function returns the expected result. Note that this uses the hard-coded list of users that we created earlier in models.user.go.
The tests for the new handlers will be similar in structure to the ones added in the previous section. The new handlers added in handlers.user.go will need the following tests:
1. TestShowLoginPageUnauthenticated
This test will check that the login page is shown to unauthenticated users as expected.
// handlers.user_test.go
func TestShowLoginPageUnauthenticated(t *testing.T){
r := getRouter(true)
r.GET("/u/login", showLoginPage)
req, _ := http.NewRequest("GET", "/u/login", nil)
testHTTPResponse(t, r, req, func(w *httptest.ResponseRecorder) bool {
statusOK := w.Code == http.StatusOK
p, err := ioutil.ReadAll(w.Body)
pageOK := err == nil && strings.Index(string(p), "<title>Login</title>") > 0
return statusOK && pageOK
})
}
2. TestLoginUnauthenticated
This test will check that a POST request to login with the correct credentials returns a success message.
//handlers.user_test.go
func TestLoginUnauthenticated(t *testing.T) {
saveLists()
w := httptest.NewRecorder()
r := getRouter(true)
r.POST("/u/login", performLogin)
loginPayload := getLoginPOSTPayload()
req, _ := http.NewRequest("POST", "/u/login", strings.NewReader(loginPayload))
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("Content-Length", strconv.Itoa(len(loginPayload)))
r.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Fail()
}
p, err := ioutil.ReadAll(w.Body)
if err != nil || strings.Index(string(p), "<title>Successful Login</title>") < 0 {
t.Fail()
}
restoreLists()
}
3. TestLoginUnauthenticatedIncorrectCredentials
This test will check that a POST request to login with incorrect credentials returns an error.
//handlers.user_test.go
func TestLoginUnauthenticatedIncorrectCredentials(t *testing.T) {
saveLists()
w := httptest.NewRecorder()
r := getRouter(true)
r.POST("/u/login", performLogin)
loginPayload := getRegistrationPOSTPayload()
req, _ := http.NewRequest("POST", "/u/login", strings.NewReader(loginPayload))
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("Content-Length", strconv.Itoa(len(loginPayload)))
r.ServeHTTP(w, req)
if w.Code != http.StatusBadRequest {
t.Fail()
}
restoreLists()
}
With these tests written, let's run them to see what happens. In your project directory, execute the following command:
go test -v
This should give the following output:
=== RUN TestShowIndexPageUnauthenticated
[GIN] 2016/09/04 - 08:33:22 | 200 | 277.294µs | | GET /
--- PASS: TestShowIndexPageUnauthenticated (0.00s)
=== RUN TestArticleUnauthenticated
[GIN] 2016/09/04 - 08:33:22 | 200 | 131.567µs | | GET /article/view/1
--- PASS: TestArticleUnauthenticated (0.00s)
=== RUN TestArticleListJSON
[GIN] 2016/09/04 - 08:33:22 | 200 | 67.678µs | | GET /
--- PASS: TestArticleListJSON (0.00s)
=== RUN TestArticleXML
[GIN] 2016/09/04 - 08:33:22 | 200 | 26.344µs | | GET /article/view/1
--- PASS: TestArticleXML (0.00s)
=== RUN TestShowRegistrationPageUnauthenticated
[GIN] 2016/09/04 - 08:33:22 | 200 | 130.407µs | | GET /u/register
--- PASS: TestShowRegistrationPageUnauthenticated (0.00s)
=== RUN TestRegisterUnauthenticated
[GIN] 2016/09/04 - 08:33:22 | 200 | 176.598µs | | POST /u/register
--- PASS: TestRegisterUnauthenticated (0.00s)
=== RUN TestRegisterUnauthenticatedUnavailableUsername
[GIN] 2016/09/04 - 08:33:22 | 400 | 181.588µs | | POST /u/register
--- PASS: TestRegisterUnauthenticatedUnavailableUsername (0.00s)
=== RUN TestShowLoginPageUnauthenticated
[GIN] 2016/09/04 - 08:33:22 | 200 | 327ns | | GET /u/login
--- FAIL: TestShowLoginPageUnauthenticated (0.00s)
=== RUN TestLoginUnauthenticated
[GIN] 2016/09/04 - 08:33:22 | 200 | 316ns | | POST /u/login
--- FAIL: TestLoginUnauthenticated (0.00s)
=== RUN TestLoginUnauthenticatedIncorrectCredentials
[GIN] 2016/09/04 - 08:33:22 | 200 | 258ns | | POST /u/login
--- FAIL: TestLoginUnauthenticatedIncorrectCredentials (0.00s)
=== RUN TestGetAllArticles
--- PASS: TestGetAllArticles (0.00s)
=== RUN TestGetArticleByID
--- PASS: TestGetArticleByID (0.00s)
=== RUN TestValidUserRegistration
--- PASS: TestValidUserRegistration (0.00s)
=== RUN TestInvalidUserRegistration
--- PASS: TestInvalidUserRegistration (0.00s)
=== RUN TestUsernameAvailability
--- PASS: TestUsernameAvailability (0.00s)
=== RUN TestUserValidity
--- FAIL: TestUserValidity (0.00s)
FAIL
exit status 1
FAIL github.com/demo-apps/go-gin-app 0.009s
As expected, the tests fail. Let's now start implementing the functionality for login and logout.