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.