0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

(go + gin) sessionを利用したMiddlewareの単体テスト

Last updated at Posted at 2024-12-04

ginでsessionを利用した認証ミドルウェアのテストコードの実装について

スマートな方法が思いつかず、力ずくな実装に。。
どなたかいい方法があるよっていう方は、コメントにてご教示ください。
よろしくお願いします。

テスト対象コード

auth_middleware.go

リクエストのセッション情報を取得し、認証が成功すれば次のハンドラーへ渡すのみ

func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		session := sessions.Default(c)
		authUserJson := session.Get("userInfo")
		if authUserJson == nil {
			c.JSON(401, domain.ErrorResponse{Message: "unauthorized"})
			c.Abort()
			return
		}
		var authUser domain.User
		if err := json.Unmarshal([]byte(authUserJson.(string)), &authUser); err != nil {
			c.JSON(401, domain.ErrorResponse{Message: "unauthorized"})
			c.Abort()
			return
		}
		c.Next()
	}
}

テストコード

方針

  1. セッション発行用のエンドポイント(public)と、要認証のエンドポイント(protected)を用意
  2. publicへリクエスト発行し、そのレスポンスからセッションを取得
  3. 取得したセッションをprotectedのリクエストのクッキーとして設定し、リクエスト発行
  4. アサート

エンドポイント

public
セッション(ID)発行用のエンドポイント

// public route
public := r.Group("/public")
public.GET("", func(c *gin.Context) {
    user := domain.User{
        ID:       1,
        Name:     "test",
        Email:    "email",
        Password: "password",
    }
    session := sessions.Default(c)
    bUser, _ := json.Marshal(user)
    session.Set("userInfo", string(bUser))
    session.Save()
    c.JSON(http.StatusOK, gin.H{"message": "success"})
})

protected
認証用ミドルウェアを通過するエンドポイント

// protected route
protected := r.Group("/protected")
protected.Use(middleware.AuthMiddleware())
protected.GET("", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"message": "success"})

リクエスト

publicへリクエスト発行し、そのレスポンスからセッションを取得

// request to the public endpoint
wPub := httptest.NewRecorder()
reqPub, _ := http.NewRequest("GET", "/public", nil)
reqPub.Header.Set("Content-Type", "application/json")
r.ServeHTTP(wPub, reqPub)

取得したセッションをprotectedのリクエストのクッキーとして設定し、リクエスト発行

// Extract session cookie from the response
sessionCookie := wPub.Header().Get("Set-Cookie")
assert.NotEmpty(t, sessionCookie, "Session cookie should not be empty")

// request to the protected endpoint
w2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/protected", nil)
req2.Header.Set("Content-Type", "application/json")
req2.Header.Set("Cookie", sessionCookie) // Attach session cookie
r.ServeHTTP(w2, req2)

テストコード全体

func TestAuthMiddleware(t *testing.T) {
	gin.SetMode(gin.TestMode)

	// session store
	store := cookie.NewStore([]byte("secret"))

	// router
	r := gin.Default()
	// session middleware
	r.Use(sessions.Sessions("sessionid", store))

	// public route
	public := r.Group("/public")
	public.GET("", func(c *gin.Context) {
		user := domain.User{
			ID:       1,
			Name:     "test",
			Email:    "email",
			Password: "password",
		}
		session := sessions.Default(c)
		bUser, _ := json.Marshal(user)
		session.Set("userInfo", string(bUser))
		session.Save()
		c.JSON(http.StatusOK, gin.H{"message": "success"})
	})

	// protected route
	protected := r.Group("/protected")
	protected.Use(middleware.AuthMiddleware())
	protected.GET("", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"message": "success"})
	})

	// test suite
	t.Run("authentication success", func(t *testing.T) {
		// request to the public endpoint
		wPub := httptest.NewRecorder()
		reqPub, _ := http.NewRequest("GET", "/public", nil)
		reqPub.Header.Set("Content-Type", "application/json")
		r.ServeHTTP(wPub, reqPub)

		// extract session cookie from the response
		sessionCookie := wPub.Header().Get("Set-Cookie")
		assert.NotEmpty(t, sessionCookie, "Session cookie should not be empty")

		// request to the protected endpoint
		w2 := httptest.NewRecorder()
		req2, _ := http.NewRequest("GET", "/protected", nil)
		req2.Header.Set("Content-Type", "application/json")
		req2.Header.Set("Cookie", sessionCookie) // Attach session cookie
		r.ServeHTTP(w2, req2)

		// assert
		assert.Equal(t, http.StatusOK, w2.Code)
		assert.JSONEq(t, `{"message":"success"}`, w2.Body.String())
	})
}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?