From 3285885b85a51b93383d7c57a339f4898411de8d Mon Sep 17 00:00:00 2001 From: Biswa Kalyan Bhuyan Date: Fri, 25 Apr 2025 15:02:00 +0530 Subject: finance/backend: feat: wrote unit/integration tests for core API endpoints --- README.md | 2 +- handlers/goal_handler_test.go | 261 ++++++++++++++++++++++++++++++++++++++++++ temp/goal_handler_test.go | 261 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 523 insertions(+), 1 deletion(-) create mode 100644 handlers/goal_handler_test.go create mode 100644 temp/goal_handler_test.go diff --git a/README.md b/README.md index e745827..b390b63 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ An application designed to help manage personal finances, including income (like * [x] Create basic CRUD APIs for Loans * [x] Create basic CRUD APIs for Goals * [x] Set up initial logging and error handling -* [ ] Write unit/integration tests for core API endpoints +* [x] Write unit/integration tests for core API endpoints **Phase 2: Frontend Foundation (React/Next.js + shadcn/ui)** diff --git a/handlers/goal_handler_test.go b/handlers/goal_handler_test.go new file mode 100644 index 0000000..0641dca --- /dev/null +++ b/handlers/goal_handler_test.go @@ -0,0 +1,261 @@ +package handlers + +import ( + "bytes" + "encoding/json" + "errors" + "finance/backend/internal/database" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" + "gorm.io/gorm" +) + +// setupTest sets up the test environment +func setupTest() (*gin.Context, *httptest.ResponseRecorder) { + gin.SetMode(gin.TestMode) + w := httptest.NewRecorder() + c, _ := gin.CreateTestContext(w) + c.Set("userID", uint(1)) + return c, w +} + +// Test basic functionality of GetGoals +func TestGetGoals(t *testing.T) { + // Save and restore the original DB + originalDB := database.DB + defer func() { + database.DB = originalDB + }() + + // Replace with a DB that returns success + mockDB := &gorm.DB{ + Error: nil, + } + database.DB = mockDB + + c, w := setupTest() + req := httptest.NewRequest("GET", "/goals", nil) + c.Request = req + + handler := NewGoalHandler() + handler.GetGoals(c) + + assert.Equal(t, http.StatusOK, w.Code) +} + +// Test basic functionality of GetGoal +func TestGetGoal(t *testing.T) { + // Save and restore the original DB + originalDB := database.DB + defer func() { + database.DB = originalDB + }() + + // Replace with a DB that returns success + mockDB := &gorm.DB{ + Error: nil, + } + database.DB = mockDB + + c, w := setupTest() + c.Params = []gin.Param{{Key: "id", Value: "1"}} + req := httptest.NewRequest("GET", "/goals/1", nil) + c.Request = req + + handler := NewGoalHandler() + handler.GetGoal(c) + + assert.Equal(t, http.StatusOK, w.Code) +} + +// Test basic functionality of CreateGoal +func TestCreateGoal(t *testing.T) { + // Save and restore the original DB + originalDB := database.DB + defer func() { + database.DB = originalDB + }() + + // Replace with a DB that returns success + mockDB := &gorm.DB{ + Error: nil, + } + database.DB = mockDB + + c, w := setupTest() + + input := CreateGoalInput{ + Name: "Test Goal", + TargetAmount: 1000, + CurrentAmount: 500, + TargetDate: "2023-12-31", + Status: "Active", + } + + inputJSON, _ := json.Marshal(input) + req := httptest.NewRequest("POST", "/goals", bytes.NewBuffer(inputJSON)) + req.Header.Set("Content-Type", "application/json") + c.Request = req + + handler := NewGoalHandler() + handler.CreateGoal(c) + + assert.Equal(t, http.StatusCreated, w.Code) +} + +// Test basic functionality of UpdateGoal +func TestUpdateGoal(t *testing.T) { + // Save and restore the original DB + originalDB := database.DB + defer func() { + database.DB = originalDB + }() + + // Replace with a DB that returns success + mockDB := &gorm.DB{ + Error: nil, + } + database.DB = mockDB + + c, w := setupTest() + c.Params = []gin.Param{{Key: "id", Value: "1"}} + + input := UpdateGoalInput{ + Name: "Updated Goal", + TargetAmount: 2000, + CurrentAmount: 1000, + Status: "Active", + } + + inputJSON, _ := json.Marshal(input) + req := httptest.NewRequest("PUT", "/goals/1", bytes.NewBuffer(inputJSON)) + req.Header.Set("Content-Type", "application/json") + c.Request = req + + handler := NewGoalHandler() + handler.UpdateGoal(c) + + assert.Equal(t, http.StatusOK, w.Code) +} + +// Test basic functionality of UpdateGoalProgress +func TestUpdateGoalProgress(t *testing.T) { + // Save and restore the original DB + originalDB := database.DB + defer func() { + database.DB = originalDB + }() + + // Replace with a DB that returns success + mockDB := &gorm.DB{ + Error: nil, + } + database.DB = mockDB + + c, w := setupTest() + c.Params = []gin.Param{{Key: "id", Value: "1"}} + + input := UpdateGoalProgressInput{ + CurrentAmount: 750, + } + + inputJSON, _ := json.Marshal(input) + req := httptest.NewRequest("PATCH", "/goals/1/progress", bytes.NewBuffer(inputJSON)) + req.Header.Set("Content-Type", "application/json") + c.Request = req + + handler := NewGoalHandler() + handler.UpdateGoalProgress(c) + + assert.Equal(t, http.StatusOK, w.Code) +} + +// Test basic functionality of DeleteGoal +func TestDeleteGoal(t *testing.T) { + // Save and restore the original DB + originalDB := database.DB + defer func() { + database.DB = originalDB + }() + + // Replace with a DB that returns success + mockDB := &gorm.DB{ + Error: nil, + } + database.DB = mockDB + + c, w := setupTest() + c.Params = []gin.Param{{Key: "id", Value: "1"}} + req := httptest.NewRequest("DELETE", "/goals/1", nil) + c.Request = req + + handler := NewGoalHandler() + handler.DeleteGoal(c) + + assert.Equal(t, http.StatusOK, w.Code) +} + +// Test error cases for each handler +func TestErrorCases(t *testing.T) { + // Save and restore the original DB + originalDB := database.DB + defer func() { + database.DB = originalDB + }() + + // Replace with a DB that returns an error + mockDB := &gorm.DB{ + Error: errors.New("database error"), + } + database.DB = mockDB + + // Test GetGoals with database error + t.Run("GetGoals_DBError", func(t *testing.T) { + c, w := setupTest() + req := httptest.NewRequest("GET", "/goals", nil) + c.Request = req + + handler := NewGoalHandler() + handler.GetGoals(c) + + assert.Equal(t, http.StatusInternalServerError, w.Code) + }) + + // Test GetGoal with database error + t.Run("GetGoal_DBError", func(t *testing.T) { + c, w := setupTest() + c.Params = []gin.Param{{Key: "id", Value: "1"}} + req := httptest.NewRequest("GET", "/goals/1", nil) + c.Request = req + + handler := NewGoalHandler() + handler.GetGoal(c) + + assert.Equal(t, http.StatusNotFound, w.Code) + }) + + // Test CreateGoal with database error + t.Run("CreateGoal_DBError", func(t *testing.T) { + c, w := setupTest() + + input := CreateGoalInput{ + Name: "Test Goal", + TargetAmount: 1000, + CurrentAmount: 500, + } + + inputJSON, _ := json.Marshal(input) + req := httptest.NewRequest("POST", "/goals", bytes.NewBuffer(inputJSON)) + req.Header.Set("Content-Type", "application/json") + c.Request = req + + handler := NewGoalHandler() + handler.CreateGoal(c) + + assert.Equal(t, http.StatusInternalServerError, w.Code) + }) +} diff --git a/temp/goal_handler_test.go b/temp/goal_handler_test.go new file mode 100644 index 0000000..0641dca --- /dev/null +++ b/temp/goal_handler_test.go @@ -0,0 +1,261 @@ +package handlers + +import ( + "bytes" + "encoding/json" + "errors" + "finance/backend/internal/database" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" + "gorm.io/gorm" +) + +// setupTest sets up the test environment +func setupTest() (*gin.Context, *httptest.ResponseRecorder) { + gin.SetMode(gin.TestMode) + w := httptest.NewRecorder() + c, _ := gin.CreateTestContext(w) + c.Set("userID", uint(1)) + return c, w +} + +// Test basic functionality of GetGoals +func TestGetGoals(t *testing.T) { + // Save and restore the original DB + originalDB := database.DB + defer func() { + database.DB = originalDB + }() + + // Replace with a DB that returns success + mockDB := &gorm.DB{ + Error: nil, + } + database.DB = mockDB + + c, w := setupTest() + req := httptest.NewRequest("GET", "/goals", nil) + c.Request = req + + handler := NewGoalHandler() + handler.GetGoals(c) + + assert.Equal(t, http.StatusOK, w.Code) +} + +// Test basic functionality of GetGoal +func TestGetGoal(t *testing.T) { + // Save and restore the original DB + originalDB := database.DB + defer func() { + database.DB = originalDB + }() + + // Replace with a DB that returns success + mockDB := &gorm.DB{ + Error: nil, + } + database.DB = mockDB + + c, w := setupTest() + c.Params = []gin.Param{{Key: "id", Value: "1"}} + req := httptest.NewRequest("GET", "/goals/1", nil) + c.Request = req + + handler := NewGoalHandler() + handler.GetGoal(c) + + assert.Equal(t, http.StatusOK, w.Code) +} + +// Test basic functionality of CreateGoal +func TestCreateGoal(t *testing.T) { + // Save and restore the original DB + originalDB := database.DB + defer func() { + database.DB = originalDB + }() + + // Replace with a DB that returns success + mockDB := &gorm.DB{ + Error: nil, + } + database.DB = mockDB + + c, w := setupTest() + + input := CreateGoalInput{ + Name: "Test Goal", + TargetAmount: 1000, + CurrentAmount: 500, + TargetDate: "2023-12-31", + Status: "Active", + } + + inputJSON, _ := json.Marshal(input) + req := httptest.NewRequest("POST", "/goals", bytes.NewBuffer(inputJSON)) + req.Header.Set("Content-Type", "application/json") + c.Request = req + + handler := NewGoalHandler() + handler.CreateGoal(c) + + assert.Equal(t, http.StatusCreated, w.Code) +} + +// Test basic functionality of UpdateGoal +func TestUpdateGoal(t *testing.T) { + // Save and restore the original DB + originalDB := database.DB + defer func() { + database.DB = originalDB + }() + + // Replace with a DB that returns success + mockDB := &gorm.DB{ + Error: nil, + } + database.DB = mockDB + + c, w := setupTest() + c.Params = []gin.Param{{Key: "id", Value: "1"}} + + input := UpdateGoalInput{ + Name: "Updated Goal", + TargetAmount: 2000, + CurrentAmount: 1000, + Status: "Active", + } + + inputJSON, _ := json.Marshal(input) + req := httptest.NewRequest("PUT", "/goals/1", bytes.NewBuffer(inputJSON)) + req.Header.Set("Content-Type", "application/json") + c.Request = req + + handler := NewGoalHandler() + handler.UpdateGoal(c) + + assert.Equal(t, http.StatusOK, w.Code) +} + +// Test basic functionality of UpdateGoalProgress +func TestUpdateGoalProgress(t *testing.T) { + // Save and restore the original DB + originalDB := database.DB + defer func() { + database.DB = originalDB + }() + + // Replace with a DB that returns success + mockDB := &gorm.DB{ + Error: nil, + } + database.DB = mockDB + + c, w := setupTest() + c.Params = []gin.Param{{Key: "id", Value: "1"}} + + input := UpdateGoalProgressInput{ + CurrentAmount: 750, + } + + inputJSON, _ := json.Marshal(input) + req := httptest.NewRequest("PATCH", "/goals/1/progress", bytes.NewBuffer(inputJSON)) + req.Header.Set("Content-Type", "application/json") + c.Request = req + + handler := NewGoalHandler() + handler.UpdateGoalProgress(c) + + assert.Equal(t, http.StatusOK, w.Code) +} + +// Test basic functionality of DeleteGoal +func TestDeleteGoal(t *testing.T) { + // Save and restore the original DB + originalDB := database.DB + defer func() { + database.DB = originalDB + }() + + // Replace with a DB that returns success + mockDB := &gorm.DB{ + Error: nil, + } + database.DB = mockDB + + c, w := setupTest() + c.Params = []gin.Param{{Key: "id", Value: "1"}} + req := httptest.NewRequest("DELETE", "/goals/1", nil) + c.Request = req + + handler := NewGoalHandler() + handler.DeleteGoal(c) + + assert.Equal(t, http.StatusOK, w.Code) +} + +// Test error cases for each handler +func TestErrorCases(t *testing.T) { + // Save and restore the original DB + originalDB := database.DB + defer func() { + database.DB = originalDB + }() + + // Replace with a DB that returns an error + mockDB := &gorm.DB{ + Error: errors.New("database error"), + } + database.DB = mockDB + + // Test GetGoals with database error + t.Run("GetGoals_DBError", func(t *testing.T) { + c, w := setupTest() + req := httptest.NewRequest("GET", "/goals", nil) + c.Request = req + + handler := NewGoalHandler() + handler.GetGoals(c) + + assert.Equal(t, http.StatusInternalServerError, w.Code) + }) + + // Test GetGoal with database error + t.Run("GetGoal_DBError", func(t *testing.T) { + c, w := setupTest() + c.Params = []gin.Param{{Key: "id", Value: "1"}} + req := httptest.NewRequest("GET", "/goals/1", nil) + c.Request = req + + handler := NewGoalHandler() + handler.GetGoal(c) + + assert.Equal(t, http.StatusNotFound, w.Code) + }) + + // Test CreateGoal with database error + t.Run("CreateGoal_DBError", func(t *testing.T) { + c, w := setupTest() + + input := CreateGoalInput{ + Name: "Test Goal", + TargetAmount: 1000, + CurrentAmount: 500, + } + + inputJSON, _ := json.Marshal(input) + req := httptest.NewRequest("POST", "/goals", bytes.NewBuffer(inputJSON)) + req.Header.Set("Content-Type", "application/json") + c.Request = req + + handler := NewGoalHandler() + handler.CreateGoal(c) + + assert.Equal(t, http.StatusInternalServerError, w.Code) + }) +} -- cgit v1.2.3-59-g8ed1b