重构 #4
| @@ -186,9 +186,26 @@ func (c *Controller) GetPlan(ctx *gin.Context) { | |||||||
| // @Failure      200 {object} controller.Response "业务失败,具体错误码和信息见响应体(例如400, 500)" | // @Failure      200 {object} controller.Response "业务失败,具体错误码和信息见响应体(例如400, 500)" | ||||||
| // @Router       /plans [get] | // @Router       /plans [get] | ||||||
| func (c *Controller) ListPlans(ctx *gin.Context) { | func (c *Controller) ListPlans(ctx *gin.Context) { | ||||||
| 	// 占位符:此处应调用服务层或仓库层来获取计划列表 | 	// 1. 调用仓库层获取所有计划 | ||||||
| 	c.logger.Infof("收到获取计划列表请求 (占位符)") | 	plans, err := c.planRepo.ListBasicPlans() | ||||||
| 	controller.SendResponse(ctx, controller.CodeSuccess, "获取计划列表接口占位符", ListPlansResponse{Plans: []PlanResponse{}, Total: 0}) | 	if err != nil { | ||||||
|  | 		c.logger.Errorf("获取计划列表失败: %v", err) | ||||||
|  | 		controller.SendErrorResponse(ctx, controller.CodeInternalError, "获取计划列表时发生内部错误") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// 2. 将模型转换为响应 DTO | ||||||
|  | 	planResponses := make([]PlanResponse, 0, len(plans)) | ||||||
|  | 	for _, p := range plans { | ||||||
|  | 		planResponses = append(planResponses, *PlanToResponse(&p)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// 3. 构造并发送成功响应 | ||||||
|  | 	resp := ListPlansResponse{ | ||||||
|  | 		Plans: planResponses, | ||||||
|  | 		Total: len(planResponses), | ||||||
|  | 	} | ||||||
|  | 	controller.SendResponse(ctx, controller.CodeSuccess, "获取计划列表成功", resp) | ||||||
| } | } | ||||||
|  |  | ||||||
| // UpdatePlan godoc | // UpdatePlan godoc | ||||||
|   | |||||||
| @@ -18,15 +18,14 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| // MockPlanRepository 是 repository.PlanRepository 的一个模拟实现,用于测试 | // MockPlanRepository 是 repository.PlanRepository 的一个模拟实现,用于测试 | ||||||
| // [保持原样,不做任何修改] |  | ||||||
| type MockPlanRepository struct { | type MockPlanRepository struct { | ||||||
| 	CreatePlanFunc     func(plan *models.Plan) error | 	CreatePlanFunc     func(plan *models.Plan) error | ||||||
| 	GetPlanByIDFunc    func(id uint) (*models.Plan, error) | 	GetPlanByIDFunc    func(id uint) (*models.Plan, error) | ||||||
| 	// ... 可以根据需要模拟其他接口方法 | 	ListBasicPlansFunc func() ([]models.Plan, error) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *MockPlanRepository) ListBasicPlans() ([]models.Plan, error) { | func (m *MockPlanRepository) ListBasicPlans() ([]models.Plan, error) { | ||||||
| 	panic("implement me") | 	return m.ListBasicPlansFunc() | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *MockPlanRepository) GetBasicPlanByID(id uint) (*models.Plan, error) { | func (m *MockPlanRepository) GetBasicPlanByID(id uint) (*models.Plan, error) { | ||||||
| @@ -60,6 +59,7 @@ func setupTestRouter(repo repository.PlanRepository) *gin.Engine { | |||||||
| 	planController := NewController(logger, repo) | 	planController := NewController(logger, repo) | ||||||
| 	router.POST("/plans", planController.CreatePlan) | 	router.POST("/plans", planController.CreatePlan) | ||||||
| 	router.GET("/plans/:id", planController.GetPlan) | 	router.GET("/plans/:id", planController.GetPlan) | ||||||
|  | 	router.GET("/plans", planController.ListPlans) | ||||||
| 	return router | 	return router | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -257,3 +257,105 @@ func TestController_GetPlan(t *testing.T) { | |||||||
| 		assert.Equal(t, "获取计划详情时发生内部错误", resp.Message) | 		assert.Equal(t, "获取计划详情时发生内部错误", resp.Message) | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // TestController_ListPlans tests the ListPlans method | ||||||
|  | func TestController_ListPlans(t *testing.T) { | ||||||
|  | 	t.Run("成功-获取计划列表", func(t *testing.T) { | ||||||
|  | 		// Arrange | ||||||
|  | 		mockPlans := []models.Plan{ | ||||||
|  | 			{Model: gorm.Model{ID: 1}, Name: "Plan 1", ContentType: models.PlanContentTypeTasks}, | ||||||
|  | 			{Model: gorm.Model{ID: 2}, Name: "Plan 2", ContentType: models.PlanContentTypeTasks}, | ||||||
|  | 		} | ||||||
|  | 		mockRepo := &MockPlanRepository{ | ||||||
|  | 			ListBasicPlansFunc: func() ([]models.Plan, error) { | ||||||
|  | 				return mockPlans, nil | ||||||
|  | 			}, | ||||||
|  | 		} | ||||||
|  | 		router := setupTestRouter(mockRepo) | ||||||
|  | 		w := httptest.NewRecorder() | ||||||
|  | 		req, _ := http.NewRequest(http.MethodGet, "/plans", 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) | ||||||
|  |  | ||||||
|  | 		dataBytes, err := json.Marshal(resp.Data) | ||||||
|  | 		assert.NoError(t, err) | ||||||
|  | 		var listResp ListPlansResponse | ||||||
|  | 		err = json.Unmarshal(dataBytes, &listResp) | ||||||
|  | 		assert.NoError(t, err) | ||||||
|  |  | ||||||
|  | 		assert.Equal(t, 2, listResp.Total) | ||||||
|  | 		assert.Len(t, listResp.Plans, 2) | ||||||
|  | 		assert.Equal(t, uint(1), listResp.Plans[0].ID) | ||||||
|  | 		assert.Equal(t, "Plan 1", listResp.Plans[0].Name) | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	t.Run("成功-返回空列表", func(t *testing.T) { | ||||||
|  | 		// Arrange | ||||||
|  | 		mockRepo := &MockPlanRepository{ | ||||||
|  | 			ListBasicPlansFunc: func() ([]models.Plan, error) { | ||||||
|  | 				return []models.Plan{}, nil | ||||||
|  | 			}, | ||||||
|  | 		} | ||||||
|  | 		router := setupTestRouter(mockRepo) | ||||||
|  | 		w := httptest.NewRecorder() | ||||||
|  | 		req, _ := http.NewRequest(http.MethodGet, "/plans", 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) | ||||||
|  |  | ||||||
|  | 		dataBytes, err := json.Marshal(resp.Data) | ||||||
|  | 		assert.NoError(t, err) | ||||||
|  | 		var listResp ListPlansResponse | ||||||
|  | 		err = json.Unmarshal(dataBytes, &listResp) | ||||||
|  | 		assert.NoError(t, err) | ||||||
|  |  | ||||||
|  | 		assert.Equal(t, 0, listResp.Total) | ||||||
|  | 		assert.Len(t, listResp.Plans, 0) | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	t.Run("失败-仓库层返回错误", func(t *testing.T) { | ||||||
|  | 		// Arrange | ||||||
|  | 		dbErr := errors.New("db error") | ||||||
|  | 		mockRepo := &MockPlanRepository{ | ||||||
|  | 			ListBasicPlansFunc: func() ([]models.Plan, error) { | ||||||
|  | 				return nil, dbErr | ||||||
|  | 			}, | ||||||
|  | 		} | ||||||
|  | 		router := setupTestRouter(mockRepo) | ||||||
|  | 		w := httptest.NewRecorder() | ||||||
|  | 		req, _ := http.NewRequest(http.MethodGet, "/plans", 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) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user