diff --git a/internal/app/controller/plan/plan_controller.go b/internal/app/controller/plan/plan_controller.go index 4f9782f..09e0ed9 100644 --- a/internal/app/controller/plan/plan_controller.go +++ b/internal/app/controller/plan/plan_controller.go @@ -235,9 +235,23 @@ func (c *Controller) UpdatePlan(ctx *gin.Context) { // @Failure 200 {object} controller.Response "业务失败,具体错误码和信息见响应体(例如400, 404, 500)" // @Router /plans/{id} [delete] func (c *Controller) DeletePlan(ctx *gin.Context) { - // 占位符:此处应调用服务层或仓库层来删除计划 - c.logger.Infof("收到删除计划请求 (占位符)") - controller.SendResponse(ctx, controller.CodeSuccess, "删除计划接口占位符", nil) + // 1. 从 URL 路径中获取 ID + idStr := ctx.Param("id") + id, err := strconv.ParseUint(idStr, 10, 32) + if err != nil { + controller.SendErrorResponse(ctx, controller.CodeBadRequest, "无效的计划ID格式") + return + } + + // 2. 调用仓库层删除计划 + if err := c.planRepo.DeletePlan(uint(id)); err != nil { + c.logger.Errorf("删除计划失败: %v", err) + controller.SendErrorResponse(ctx, controller.CodeInternalError, "删除计划时发生内部错误") + return + } + + // 3. 发送成功响应 + controller.SendResponse(ctx, controller.CodeSuccess, "计划删除成功", nil) } // StartPlan godoc diff --git a/internal/app/controller/plan/plan_controller_test.go b/internal/app/controller/plan/plan_controller_test.go index b20a7af..f4a535a 100644 --- a/internal/app/controller/plan/plan_controller_test.go +++ b/internal/app/controller/plan/plan_controller_test.go @@ -22,6 +22,7 @@ type MockPlanRepository struct { CreatePlanFunc func(plan *models.Plan) error GetPlanByIDFunc func(id uint) (*models.Plan, error) ListBasicPlansFunc func() ([]models.Plan, error) + DeletePlanFunc func(id uint) error } func (m *MockPlanRepository) ListBasicPlans() ([]models.Plan, error) { @@ -48,7 +49,7 @@ func (m *MockPlanRepository) UpdatePlan(plan *models.Plan) error { } func (m *MockPlanRepository) DeletePlan(id uint) error { - panic("implement me") + return m.DeletePlanFunc(id) } // setupTestRouter 创建一个用于测试的 gin 引擎和控制器实例 @@ -60,6 +61,7 @@ func setupTestRouter(repo repository.PlanRepository) *gin.Engine { router.POST("/plans", planController.CreatePlan) router.GET("/plans/:id", planController.GetPlan) router.GET("/plans", planController.ListPlans) + router.DELETE("/plans/:id", planController.DeletePlan) return router } @@ -359,3 +361,105 @@ func TestController_ListPlans(t *testing.T) { assert.Equal(t, "获取计划列表时发生内部错误", resp.Message) }) } + +// TestController_DeletePlan 是 DeletePlan 的单元测试 +func TestController_DeletePlan(t *testing.T) { + t.Run("成功-删除计划", func(t *testing.T) { + // Arrange + mockRepo := &MockPlanRepository{ + DeletePlanFunc: func(id uint) error { + assert.Equal(t, uint(1), id) + return nil // Simulate successful deletion + }, + } + router := setupTestRouter(mockRepo) + w := httptest.NewRecorder() + req, _ := http.NewRequest(http.MethodDelete, "/plans/1", nil) + + // Act + router.ServeHTTP(w, req) + + // Assert + assert.Equal(t, http.StatusOK, w.Code) + + var resp controller.Response + err := json.Unmarshal(w.Body.Bytes(), &resp) + assert.NoError(t, err) + + assert.Equal(t, controller.CodeSuccess, resp.Code) + assert.Equal(t, "计划删除成功", resp.Message) + assert.Nil(t, resp.Data) + }) + + t.Run("失败-计划不存在", func(t *testing.T) { + // Arrange + mockRepo := &MockPlanRepository{ + DeletePlanFunc: func(id uint) error { + return gorm.ErrRecordNotFound // Simulate not found + }, + } + router := setupTestRouter(mockRepo) + w := httptest.NewRecorder() + req, _ := http.NewRequest(http.MethodDelete, "/plans/999", nil) + + // Act + router.ServeHTTP(w, req) + + // Assert + assert.Equal(t, http.StatusOK, w.Code) + + var resp controller.Response + err := json.Unmarshal(w.Body.Bytes(), &resp) + assert.NoError(t, err) + + assert.Equal(t, controller.CodeInternalError, resp.Code) + assert.Equal(t, "删除计划时发生内部错误", resp.Message) + }) + + t.Run("失败-无效的ID格式", func(t *testing.T) { + // Arrange + mockRepo := &MockPlanRepository{} // No repo call expected + router := setupTestRouter(mockRepo) + w := httptest.NewRecorder() + req, _ := http.NewRequest(http.MethodDelete, "/plans/abc", nil) + + // Act + router.ServeHTTP(w, req) + + // Assert + assert.Equal(t, http.StatusOK, w.Code) + + var resp controller.Response + err := json.Unmarshal(w.Body.Bytes(), &resp) + assert.NoError(t, err) + + assert.Equal(t, controller.CodeBadRequest, resp.Code) + assert.Equal(t, "无效的计划ID格式", resp.Message) + }) + + t.Run("失败-仓库层内部错误", func(t *testing.T) { + // Arrange + internalErr := errors.New("something went wrong") + mockRepo := &MockPlanRepository{ + DeletePlanFunc: func(id uint) error { + return internalErr // Simulate internal error + }, + } + router := setupTestRouter(mockRepo) + w := httptest.NewRecorder() + req, _ := http.NewRequest(http.MethodDelete, "/plans/1", nil) + + // Act + router.ServeHTTP(w, req) + + // Assert + assert.Equal(t, http.StatusOK, w.Code) + + var resp controller.Response + err := json.Unmarshal(w.Body.Bytes(), &resp) + assert.NoError(t, err) + + assert.Equal(t, controller.CodeInternalError, resp.Code) + assert.Equal(t, "删除计划时发生内部错误", resp.Message) + }) +}