实现 UpdatePlan 和单测
This commit is contained in:
@@ -220,9 +220,60 @@ func (c *Controller) ListPlans(ctx *gin.Context) {
|
|||||||
// @Failure 200 {object} controller.Response "业务失败,具体错误码和信息见响应体(例如400, 404, 500)"
|
// @Failure 200 {object} controller.Response "业务失败,具体错误码和信息见响应体(例如400, 404, 500)"
|
||||||
// @Router /plans/{id} [put]
|
// @Router /plans/{id} [put]
|
||||||
func (c *Controller) UpdatePlan(ctx *gin.Context) {
|
func (c *Controller) UpdatePlan(ctx *gin.Context) {
|
||||||
// 占位符:此处应调用服务层或仓库层来更新计划
|
// 1. 从 URL 路径中获取 ID
|
||||||
c.logger.Infof("收到更新计划请求 (占位符)")
|
idStr := ctx.Param("id")
|
||||||
controller.SendResponse(ctx, controller.CodeSuccess, "更新计划接口占位符", PlanResponse{ID: 0, Name: "占位计划"})
|
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
controller.SendErrorResponse(ctx, controller.CodeBadRequest, "无效的计划ID格式")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 绑定请求体
|
||||||
|
var req UpdatePlanRequest
|
||||||
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||||
|
controller.SendErrorResponse(ctx, controller.CodeBadRequest, "无效的请求体: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 将请求转换为模型(转换函数带校验)
|
||||||
|
planToUpdate, err := PlanFromUpdateRequest(&req)
|
||||||
|
if err != nil {
|
||||||
|
controller.SendErrorResponse(ctx, controller.CodeBadRequest, "计划数据校验失败: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
planToUpdate.ID = uint(id) // 确保ID被设置
|
||||||
|
|
||||||
|
// 4. 检查计划是否存在
|
||||||
|
_, err = c.planRepo.GetBasicPlanByID(uint(id))
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
controller.SendErrorResponse(ctx, controller.CodeNotFound, "计划不存在")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.logger.Errorf("获取计划详情失败: %v", err)
|
||||||
|
controller.SendErrorResponse(ctx, controller.CodeInternalError, "获取计划详情时发生内部错误")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 调用仓库方法更新计划
|
||||||
|
if err := c.planRepo.UpdatePlan(planToUpdate); err != nil {
|
||||||
|
controller.SendErrorResponse(ctx, controller.CodeBadRequest, "更新计划失败: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 获取更新后的完整计划用于响应
|
||||||
|
updatedPlan, err := c.planRepo.GetPlanByID(uint(id))
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Errorf("获取更新后的计划详情失败: %v", err)
|
||||||
|
controller.SendErrorResponse(ctx, controller.CodeInternalError, "获取更新后计划详情时发生内部错误")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 将模型转换为响应 DTO
|
||||||
|
resp := PlanToResponse(updatedPlan)
|
||||||
|
|
||||||
|
// 8. 发送成功响应
|
||||||
|
controller.SendResponse(ctx, controller.CodeSuccess, "计划更新成功", resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeletePlan godoc
|
// DeletePlan godoc
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller"
|
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller"
|
||||||
@@ -19,35 +20,46 @@ import (
|
|||||||
|
|
||||||
// MockPlanRepository 是 repository.PlanRepository 的一个模拟实现,用于测试
|
// MockPlanRepository 是 repository.PlanRepository 的一个模拟实现,用于测试
|
||||||
type MockPlanRepository struct {
|
type MockPlanRepository struct {
|
||||||
CreatePlanFunc func(plan *models.Plan) error
|
// CreatePlanFunc 模拟 CreatePlan 方法的行为
|
||||||
GetPlanByIDFunc func(id uint) (*models.Plan, error)
|
CreatePlanFunc func(plan *models.Plan) error
|
||||||
|
// GetPlanByIDFunc 模拟 GetPlanByID 方法的行为
|
||||||
|
GetPlanByIDFunc func(id uint) (*models.Plan, error)
|
||||||
|
// GetBasicPlanByIDFunc 模拟 GetBasicPlanByID 方法的行为
|
||||||
|
GetBasicPlanByIDFunc func(id uint) (*models.Plan, error)
|
||||||
|
// ListBasicPlansFunc 模拟 ListBasicPlans 方法的行为
|
||||||
ListBasicPlansFunc func() ([]models.Plan, error)
|
ListBasicPlansFunc func() ([]models.Plan, error)
|
||||||
DeletePlanFunc func(id uint) error
|
// UpdatePlanFunc 模拟 UpdatePlan 方法的行为
|
||||||
|
UpdatePlanFunc func(plan *models.Plan) error
|
||||||
|
// DeletePlanFunc 模拟 DeletePlan 方法的行为
|
||||||
|
DeletePlanFunc func(id uint) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListBasicPlans 实现了 MockPlanRepository 接口的 ListBasicPlans 方法
|
||||||
func (m *MockPlanRepository) ListBasicPlans() ([]models.Plan, error) {
|
func (m *MockPlanRepository) ListBasicPlans() ([]models.Plan, error) {
|
||||||
return m.ListBasicPlansFunc()
|
return m.ListBasicPlansFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBasicPlanByID 实现了 MockPlanRepository 接口的 GetBasicPlanByID 方法
|
||||||
func (m *MockPlanRepository) GetBasicPlanByID(id uint) (*models.Plan, error) {
|
func (m *MockPlanRepository) GetBasicPlanByID(id uint) (*models.Plan, error) {
|
||||||
panic("implement me")
|
return m.GetBasicPlanByIDFunc(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPlanByID 实现了 MockPlanRepository 接口的 GetPlanByID 方法
|
||||||
func (m *MockPlanRepository) GetPlanByID(id uint) (*models.Plan, error) {
|
func (m *MockPlanRepository) GetPlanByID(id uint) (*models.Plan, error) {
|
||||||
return m.GetPlanByIDFunc(id)
|
return m.GetPlanByIDFunc(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreatePlan 实现了 MockPlanRepository 接口的 CreatePlan 方法
|
||||||
func (m *MockPlanRepository) CreatePlan(plan *models.Plan) error {
|
func (m *MockPlanRepository) CreatePlan(plan *models.Plan) error {
|
||||||
if m.CreatePlanFunc != nil {
|
return m.CreatePlanFunc(plan)
|
||||||
return m.CreatePlanFunc(plan)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdatePlan 实现了 MockPlanRepository 接口的 UpdatePlan 方法
|
||||||
func (m *MockPlanRepository) UpdatePlan(plan *models.Plan) error {
|
func (m *MockPlanRepository) UpdatePlan(plan *models.Plan) error {
|
||||||
panic("implement me")
|
return m.UpdatePlanFunc(plan)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeletePlan 实现了 MockPlanRepository 接口的 DeletePlan 方法
|
||||||
func (m *MockPlanRepository) DeletePlan(id uint) error {
|
func (m *MockPlanRepository) DeletePlan(id uint) error {
|
||||||
return m.DeletePlanFunc(id)
|
return m.DeletePlanFunc(id)
|
||||||
}
|
}
|
||||||
@@ -61,14 +73,16 @@ func setupTestRouter(repo repository.PlanRepository) *gin.Engine {
|
|||||||
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)
|
router.GET("/plans", planController.ListPlans)
|
||||||
|
router.PUT("/plans/:id", planController.UpdatePlan)
|
||||||
router.DELETE("/plans/:id", planController.DeletePlan)
|
router.DELETE("/plans/:id", planController.DeletePlan)
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestController_CreatePlan [保持原样,不做任何修改]
|
// TestController_CreatePlan 测试 CreatePlan 方法
|
||||||
func TestController_CreatePlan(t *testing.T) {
|
func TestController_CreatePlan(t *testing.T) {
|
||||||
t.Run("成功-创建包含任务的计划", func(t *testing.T) {
|
t.Run("成功-创建包含任务的计划", func(t *testing.T) {
|
||||||
// Arrange
|
// Arrange (准备阶段)
|
||||||
|
// 模拟仓库行为:CreatePlan 成功时,为计划和任务分配ID
|
||||||
mockRepo := &MockPlanRepository{
|
mockRepo := &MockPlanRepository{
|
||||||
CreatePlanFunc: func(plan *models.Plan) error {
|
CreatePlanFunc: func(plan *models.Plan) error {
|
||||||
plan.ID = 1
|
plan.ID = 1
|
||||||
@@ -79,8 +93,10 @@ func TestController_CreatePlan(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
// 设置 Gin 路由器,并注入模拟仓库
|
||||||
router := setupTestRouter(mockRepo)
|
router := setupTestRouter(mockRepo)
|
||||||
|
|
||||||
|
// 准备请求体
|
||||||
reqBody := CreatePlanRequest{
|
reqBody := CreatePlanRequest{
|
||||||
Name: "Test Plan with Tasks",
|
Name: "Test Plan with Tasks",
|
||||||
ExecutionType: models.PlanExecutionTypeManual,
|
ExecutionType: models.PlanExecutionTypeManual,
|
||||||
@@ -91,23 +107,29 @@ func TestController_CreatePlan(t *testing.T) {
|
|||||||
}
|
}
|
||||||
bodyBytes, _ := json.Marshal(reqBody)
|
bodyBytes, _ := json.Marshal(reqBody)
|
||||||
|
|
||||||
|
// 创建 HTTP 请求
|
||||||
req, _ := http.NewRequest(http.MethodPost, "/plans", bytes.NewBuffer(bodyBytes))
|
req, _ := http.NewRequest(http.MethodPost, "/plans", bytes.NewBuffer(bodyBytes))
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
// Act
|
// Act (执行阶段)
|
||||||
|
// 发送 HTTP 请求到路由器
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
// Assert
|
// Assert (断言阶段)
|
||||||
|
// 验证 HTTP 状态码
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
|
// 解析响应体
|
||||||
var resp controller.Response
|
var resp controller.Response
|
||||||
err := json.Unmarshal(w.Body.Bytes(), &resp)
|
err := json.Unmarshal(w.Body.Bytes(), &resp)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// 验证业务响应码和消息
|
||||||
assert.Equal(t, controller.CodeCreated, resp.Code)
|
assert.Equal(t, controller.CodeCreated, resp.Code)
|
||||||
assert.Equal(t, "计划创建成功", resp.Message)
|
assert.Equal(t, "计划创建成功", resp.Message)
|
||||||
|
|
||||||
|
// 验证返回数据中的计划ID
|
||||||
dataMap, ok := resp.Data.(map[string]interface{})
|
dataMap, ok := resp.Data.(map[string]interface{})
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.Equal(t, float64(1), dataMap["id"])
|
assert.Equal(t, float64(1), dataMap["id"])
|
||||||
@@ -117,7 +139,8 @@ func TestController_CreatePlan(t *testing.T) {
|
|||||||
// TestController_GetPlan 是为 GetPlan 方法新增的单元测试函数
|
// TestController_GetPlan 是为 GetPlan 方法新增的单元测试函数
|
||||||
func TestController_GetPlan(t *testing.T) {
|
func TestController_GetPlan(t *testing.T) {
|
||||||
t.Run("成功-获取计划详情", func(t *testing.T) {
|
t.Run("成功-获取计划详情", func(t *testing.T) {
|
||||||
// Arrange
|
// Arrange (准备阶段)
|
||||||
|
// 模拟仓库行为:GetPlanByID 成功时返回一个计划
|
||||||
mockRepo := &MockPlanRepository{
|
mockRepo := &MockPlanRepository{
|
||||||
GetPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
GetPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
||||||
assert.Equal(t, uint(1), id)
|
assert.Equal(t, uint(1), id)
|
||||||
@@ -128,14 +151,16 @@ func TestController_GetPlan(t *testing.T) {
|
|||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
// 设置 Gin 路由器
|
||||||
router := setupTestRouter(mockRepo)
|
router := setupTestRouter(mockRepo)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
// 创建 HTTP 请求
|
||||||
req, _ := http.NewRequest(http.MethodGet, "/plans/1", nil)
|
req, _ := http.NewRequest(http.MethodGet, "/plans/1", nil)
|
||||||
|
|
||||||
// Act
|
// Act (执行阶段)
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
// Assert
|
// Assert (断言阶段)
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
var resp controller.Response
|
var resp controller.Response
|
||||||
@@ -149,7 +174,8 @@ func TestController_GetPlan(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("成功-获取内容为空的计划详情", func(t *testing.T) {
|
t.Run("成功-获取内容为空的计划详情", func(t *testing.T) {
|
||||||
// Arrange
|
// Arrange (准备阶段)
|
||||||
|
// 模拟仓库行为:GetPlanByID 成功时返回一个任务列表为空的计划
|
||||||
mockRepo := &MockPlanRepository{
|
mockRepo := &MockPlanRepository{
|
||||||
GetPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
GetPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
||||||
assert.Equal(t, uint(3), id)
|
assert.Equal(t, uint(3), id)
|
||||||
@@ -165,10 +191,10 @@ func TestController_GetPlan(t *testing.T) {
|
|||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
req, _ := http.NewRequest(http.MethodGet, "/plans/3", nil)
|
req, _ := http.NewRequest(http.MethodGet, "/plans/3", nil)
|
||||||
|
|
||||||
// Act
|
// Act (执行阶段)
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
// Assert
|
// Assert (断言阶段)
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
var resp controller.Response
|
var resp controller.Response
|
||||||
@@ -188,7 +214,8 @@ func TestController_GetPlan(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("失败-计划不存在", func(t *testing.T) {
|
t.Run("失败-计划不存在", func(t *testing.T) {
|
||||||
// Arrange
|
// Arrange (准备阶段)
|
||||||
|
// 模拟仓库行为:GetPlanByID 返回记录未找到错误
|
||||||
mockRepo := &MockPlanRepository{
|
mockRepo := &MockPlanRepository{
|
||||||
GetPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
GetPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
||||||
return nil, gorm.ErrRecordNotFound
|
return nil, gorm.ErrRecordNotFound
|
||||||
@@ -198,10 +225,10 @@ func TestController_GetPlan(t *testing.T) {
|
|||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
req, _ := http.NewRequest(http.MethodGet, "/plans/999", nil)
|
req, _ := http.NewRequest(http.MethodGet, "/plans/999", nil)
|
||||||
|
|
||||||
// Act
|
// Act (执行阶段)
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
// Assert
|
// Assert (断言阶段)
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
var resp controller.Response
|
var resp controller.Response
|
||||||
@@ -213,16 +240,18 @@ func TestController_GetPlan(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("失败-无效的ID格式", func(t *testing.T) {
|
t.Run("失败-无效的ID格式", func(t *testing.T) {
|
||||||
// Arrange
|
// Arrange (准备阶段)
|
||||||
|
// 模拟仓库为空,因为预期不会调用仓库方法
|
||||||
mockRepo := &MockPlanRepository{}
|
mockRepo := &MockPlanRepository{}
|
||||||
router := setupTestRouter(mockRepo)
|
router := setupTestRouter(mockRepo)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
// 创建带有无效ID格式的 HTTP 请求
|
||||||
req, _ := http.NewRequest(http.MethodGet, "/plans/abc", nil)
|
req, _ := http.NewRequest(http.MethodGet, "/plans/abc", nil)
|
||||||
|
|
||||||
// Act
|
// Act (执行阶段)
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
// Assert
|
// Assert (断言阶段)
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
var resp controller.Response
|
var resp controller.Response
|
||||||
@@ -234,8 +263,9 @@ func TestController_GetPlan(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("失败-仓库层内部错误", func(t *testing.T) {
|
t.Run("失败-仓库层内部错误", func(t *testing.T) {
|
||||||
// Arrange
|
// Arrange (准备阶段)
|
||||||
internalErr := errors.New("database connection lost")
|
internalErr := errors.New("database connection lost")
|
||||||
|
// 模拟仓库行为:GetPlanByID 返回内部错误
|
||||||
mockRepo := &MockPlanRepository{
|
mockRepo := &MockPlanRepository{
|
||||||
GetPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
GetPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
||||||
return nil, internalErr
|
return nil, internalErr
|
||||||
@@ -245,10 +275,10 @@ func TestController_GetPlan(t *testing.T) {
|
|||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
req, _ := http.NewRequest(http.MethodGet, "/plans/1", nil)
|
req, _ := http.NewRequest(http.MethodGet, "/plans/1", nil)
|
||||||
|
|
||||||
// Act
|
// Act (执行阶段)
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
// Assert
|
// Assert (断言阶段)
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
var resp controller.Response
|
var resp controller.Response
|
||||||
@@ -260,14 +290,16 @@ func TestController_GetPlan(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestController_ListPlans tests the ListPlans method
|
// TestController_ListPlans 测试 ListPlans 方法
|
||||||
func TestController_ListPlans(t *testing.T) {
|
func TestController_ListPlans(t *testing.T) {
|
||||||
t.Run("成功-获取计划列表", func(t *testing.T) {
|
t.Run("成功-获取计划列表", func(t *testing.T) {
|
||||||
// Arrange
|
// Arrange (准备阶段)
|
||||||
|
// 模拟返回的计划列表
|
||||||
mockPlans := []models.Plan{
|
mockPlans := []models.Plan{
|
||||||
{Model: gorm.Model{ID: 1}, Name: "Plan 1", ContentType: models.PlanContentTypeTasks},
|
{Model: gorm.Model{ID: 1}, Name: "Plan 1", ContentType: models.PlanContentTypeTasks},
|
||||||
{Model: gorm.Model{ID: 2}, Name: "Plan 2", ContentType: models.PlanContentTypeTasks},
|
{Model: gorm.Model{ID: 2}, Name: "Plan 2", ContentType: models.PlanContentTypeTasks},
|
||||||
}
|
}
|
||||||
|
// 模拟仓库行为:ListBasicPlans 成功时返回计划列表
|
||||||
mockRepo := &MockPlanRepository{
|
mockRepo := &MockPlanRepository{
|
||||||
ListBasicPlansFunc: func() ([]models.Plan, error) {
|
ListBasicPlansFunc: func() ([]models.Plan, error) {
|
||||||
return mockPlans, nil
|
return mockPlans, nil
|
||||||
@@ -277,10 +309,10 @@ func TestController_ListPlans(t *testing.T) {
|
|||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
req, _ := http.NewRequest(http.MethodGet, "/plans", nil)
|
req, _ := http.NewRequest(http.MethodGet, "/plans", nil)
|
||||||
|
|
||||||
// Act
|
// Act (执行阶段)
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
// Assert
|
// Assert (断言阶段)
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
var resp controller.Response
|
var resp controller.Response
|
||||||
@@ -303,7 +335,8 @@ func TestController_ListPlans(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("成功-返回空列表", func(t *testing.T) {
|
t.Run("成功-返回空列表", func(t *testing.T) {
|
||||||
// Arrange
|
// Arrange (准备阶段)
|
||||||
|
// 模拟仓库行为:ListBasicPlans 返回空列表
|
||||||
mockRepo := &MockPlanRepository{
|
mockRepo := &MockPlanRepository{
|
||||||
ListBasicPlansFunc: func() ([]models.Plan, error) {
|
ListBasicPlansFunc: func() ([]models.Plan, error) {
|
||||||
return []models.Plan{}, nil
|
return []models.Plan{}, nil
|
||||||
@@ -313,10 +346,10 @@ func TestController_ListPlans(t *testing.T) {
|
|||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
req, _ := http.NewRequest(http.MethodGet, "/plans", nil)
|
req, _ := http.NewRequest(http.MethodGet, "/plans", nil)
|
||||||
|
|
||||||
// Act
|
// Act (执行阶段)
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
// Assert
|
// Assert (断言阶段)
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
var resp controller.Response
|
var resp controller.Response
|
||||||
@@ -336,8 +369,9 @@ func TestController_ListPlans(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("失败-仓库层返回错误", func(t *testing.T) {
|
t.Run("失败-仓库层返回错误", func(t *testing.T) {
|
||||||
// Arrange
|
// Arrange (准备阶段)
|
||||||
dbErr := errors.New("db error")
|
dbErr := errors.New("db error")
|
||||||
|
// 模拟仓库行为:ListBasicPlans 返回数据库错误
|
||||||
mockRepo := &MockPlanRepository{
|
mockRepo := &MockPlanRepository{
|
||||||
ListBasicPlansFunc: func() ([]models.Plan, error) {
|
ListBasicPlansFunc: func() ([]models.Plan, error) {
|
||||||
return nil, dbErr
|
return nil, dbErr
|
||||||
@@ -347,10 +381,10 @@ func TestController_ListPlans(t *testing.T) {
|
|||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
req, _ := http.NewRequest(http.MethodGet, "/plans", nil)
|
req, _ := http.NewRequest(http.MethodGet, "/plans", nil)
|
||||||
|
|
||||||
// Act
|
// Act (执行阶段)
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
// Assert
|
// Assert (断言阶段)
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
var resp controller.Response
|
var resp controller.Response
|
||||||
@@ -362,24 +396,347 @@ func TestController_ListPlans(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestController_UpdatePlan 是 UpdatePlan 的测试函数
|
||||||
|
func TestController_UpdatePlan(t *testing.T) {
|
||||||
|
t.Run("成功-更新计划", func(t *testing.T) {
|
||||||
|
// Arrange (准备阶段)
|
||||||
|
planID := uint(1)
|
||||||
|
updatedName := "Updated Plan Name"
|
||||||
|
// 模拟一个已存在的计划
|
||||||
|
mockPlan := &models.Plan{
|
||||||
|
Model: gorm.Model{ID: planID},
|
||||||
|
Name: "Original Plan",
|
||||||
|
Description: "Original Description",
|
||||||
|
ContentType: models.PlanContentTypeTasks,
|
||||||
|
}
|
||||||
|
// 配置模拟仓库的行为
|
||||||
|
mockRepo := &MockPlanRepository{
|
||||||
|
// 模拟 GetBasicPlanByID 成功返回现有计划
|
||||||
|
GetBasicPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
||||||
|
assert.Equal(t, planID, id)
|
||||||
|
return mockPlan, nil
|
||||||
|
},
|
||||||
|
// 模拟 UpdatePlan 成功更新计划,并更新 mockPlan 的名称
|
||||||
|
UpdatePlanFunc: func(plan *models.Plan) error {
|
||||||
|
assert.Equal(t, planID, plan.ID)
|
||||||
|
assert.Equal(t, updatedName, plan.Name)
|
||||||
|
mockPlan.Name = plan.Name // 模拟更新操作
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
// 模拟 GetPlanByID 返回更新后的计划
|
||||||
|
GetPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
||||||
|
assert.Equal(t, planID, id)
|
||||||
|
return mockPlan, nil // 返回已更新的 mockPlan
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// 设置 Gin 路由器,并注入模拟仓库
|
||||||
|
router := setupTestRouter(mockRepo)
|
||||||
|
|
||||||
|
// 准备更新请求体
|
||||||
|
reqBody := UpdatePlanRequest{
|
||||||
|
Name: updatedName,
|
||||||
|
Description: "Updated Description",
|
||||||
|
ExecutionType: models.PlanExecutionTypeAutomatic,
|
||||||
|
ContentType: models.PlanContentTypeTasks,
|
||||||
|
}
|
||||||
|
bodyBytes, _ := json.Marshal(reqBody)
|
||||||
|
|
||||||
|
// 创建 HTTP PUT 请求
|
||||||
|
req, _ := http.NewRequest(http.MethodPut, "/plans/"+strconv.Itoa(int(planID)), bytes.NewBuffer(bodyBytes))
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
// Act (执行阶段)
|
||||||
|
// 发送 HTTP 请求到路由器
|
||||||
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
// Assert (断言阶段)
|
||||||
|
// 验证 HTTP 状态码
|
||||||
|
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)
|
||||||
|
|
||||||
|
dataMap, ok := resp.Data.(map[string]interface{})
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, float64(planID), dataMap["id"])
|
||||||
|
assert.Equal(t, updatedName, dataMap["name"])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("失败-无效的ID格式", func(t *testing.T) {
|
||||||
|
// Arrange (准备阶段)
|
||||||
|
// 模拟仓库为空,因为预期不会调用仓库方法
|
||||||
|
mockRepo := &MockPlanRepository{}
|
||||||
|
router := setupTestRouter(mockRepo)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
// 创建带有无效ID格式的 HTTP PUT 请求
|
||||||
|
req, _ := http.NewRequest(http.MethodPut, "/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 (准备阶段)
|
||||||
|
planID := uint(1)
|
||||||
|
// 模拟仓库为空,因为预期不会调用仓库方法(请求体绑定失败发生在控制器内部)
|
||||||
|
mockRepo := &MockPlanRepository{}
|
||||||
|
router := setupTestRouter(mockRepo)
|
||||||
|
|
||||||
|
// 准备一个无效的 JSON 请求体,例如 execution_type 类型错误
|
||||||
|
reqBody := `{\"name\": \"Updated Plan Name\",}`
|
||||||
|
req, _ := http.NewRequest(http.MethodPut, "/plans/"+strconv.Itoa(int(planID)), bytes.NewBufferString(reqBody))
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
// 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.Contains(t, resp.Message, "无效的请求体")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("失败-计划不存在", func(t *testing.T) {
|
||||||
|
// Arrange (准备阶段)
|
||||||
|
planID := uint(999)
|
||||||
|
// 模拟仓库行为:GetBasicPlanByID 返回记录未找到错误
|
||||||
|
mockRepo := &MockPlanRepository{
|
||||||
|
GetBasicPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
||||||
|
assert.Equal(t, planID, id)
|
||||||
|
return nil, gorm.ErrRecordNotFound
|
||||||
|
},
|
||||||
|
}
|
||||||
|
router := setupTestRouter(mockRepo)
|
||||||
|
|
||||||
|
// 准备有效的请求体
|
||||||
|
reqBody := UpdatePlanRequest{
|
||||||
|
Name: "Updated Plan Name",
|
||||||
|
Description: "Updated Description",
|
||||||
|
ExecutionType: models.PlanExecutionTypeAutomatic,
|
||||||
|
ContentType: models.PlanContentTypeTasks,
|
||||||
|
}
|
||||||
|
bodyBytes, _ := json.Marshal(reqBody)
|
||||||
|
|
||||||
|
// 创建 HTTP PUT 请求
|
||||||
|
req, _ := http.NewRequest(http.MethodPut, "/plans/"+strconv.Itoa(int(planID)), bytes.NewBuffer(bodyBytes))
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
// 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.CodeNotFound, resp.Code)
|
||||||
|
assert.Equal(t, "计划不存在", resp.Message)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("失败-计划数据校验失败", func(t *testing.T) {
|
||||||
|
// Arrange (准备阶段)
|
||||||
|
planID := uint(1)
|
||||||
|
// 模拟一个已存在的计划
|
||||||
|
mockPlan := &models.Plan{
|
||||||
|
Model: gorm.Model{ID: planID},
|
||||||
|
Name: "Original Plan",
|
||||||
|
Description: "Original Description",
|
||||||
|
ContentType: models.PlanContentTypeTasks,
|
||||||
|
}
|
||||||
|
// 配置模拟仓库行为:GetBasicPlanByID 成功返回现有计划
|
||||||
|
mockRepo := &MockPlanRepository{
|
||||||
|
GetBasicPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
||||||
|
return mockPlan, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
router := setupTestRouter(mockRepo)
|
||||||
|
|
||||||
|
// 准备一个会导致 PlanFromUpdateRequest 校验失败的请求体。
|
||||||
|
// 这里通过提供重复的 ExecutionOrder 来触发 ValidateExecutionOrder 错误。
|
||||||
|
reqBody := UpdatePlanRequest{
|
||||||
|
Name: "Invalid Plan",
|
||||||
|
ExecutionType: models.PlanExecutionTypeAutomatic,
|
||||||
|
ContentType: models.PlanContentTypeTasks, // 设置为任务类型
|
||||||
|
Tasks: []TaskRequest{
|
||||||
|
{Name: "Task 1", ExecutionOrder: 1, Type: models.TaskTypeWaiting},
|
||||||
|
{Name: "Task 2", ExecutionOrder: 1, Type: models.TaskTypeWaiting}, // 重复的执行顺序
|
||||||
|
},
|
||||||
|
}
|
||||||
|
bodyBytes, _ := json.Marshal(reqBody)
|
||||||
|
|
||||||
|
// 创建 HTTP PUT 请求
|
||||||
|
req, _ := http.NewRequest(http.MethodPut, "/plans/"+strconv.Itoa(int(planID)), bytes.NewBuffer(bodyBytes))
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
// 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.Contains(t, resp.Message, "计划数据校验失败")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("失败-仓库层更新失败", func(t *testing.T) {
|
||||||
|
// Arrange (准备阶段)
|
||||||
|
planID := uint(1)
|
||||||
|
// 模拟一个已存在的计划
|
||||||
|
mockPlan := &models.Plan{
|
||||||
|
Model: gorm.Model{ID: planID},
|
||||||
|
Name: "Original Plan",
|
||||||
|
Description: "Original Description",
|
||||||
|
ContentType: models.PlanContentTypeTasks,
|
||||||
|
}
|
||||||
|
updateErr := errors.New("failed to update in repository")
|
||||||
|
// 配置模拟仓库行为
|
||||||
|
mockRepo := &MockPlanRepository{
|
||||||
|
// 模拟 GetBasicPlanByID 成功返回现有计划
|
||||||
|
GetBasicPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
||||||
|
return mockPlan, nil
|
||||||
|
},
|
||||||
|
// 模拟 UpdatePlan 返回更新失败错误
|
||||||
|
UpdatePlanFunc: func(plan *models.Plan) error {
|
||||||
|
return updateErr // 模拟更新失败
|
||||||
|
},
|
||||||
|
}
|
||||||
|
router := setupTestRouter(mockRepo)
|
||||||
|
|
||||||
|
// 准备有效的请求体
|
||||||
|
reqBody := UpdatePlanRequest{
|
||||||
|
Name: "Updated Plan Name",
|
||||||
|
Description: "Updated Description",
|
||||||
|
ExecutionType: models.PlanExecutionTypeAutomatic,
|
||||||
|
ContentType: models.PlanContentTypeTasks,
|
||||||
|
}
|
||||||
|
bodyBytes, _ := json.Marshal(reqBody)
|
||||||
|
|
||||||
|
// 创建 HTTP PUT 请求
|
||||||
|
req, _ := http.NewRequest(http.MethodPut, "/plans/"+strconv.Itoa(int(planID)), bytes.NewBuffer(bodyBytes))
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
// 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, "更新计划失败: "+updateErr.Error(), resp.Message)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("失败-获取更新后计划失败", func(t *testing.T) {
|
||||||
|
// Arrange (准备阶段)
|
||||||
|
planID := uint(1)
|
||||||
|
// 模拟一个已存在的计划
|
||||||
|
mockPlan := &models.Plan{
|
||||||
|
Model: gorm.Model{ID: planID},
|
||||||
|
Name: "Original Plan",
|
||||||
|
Description: "Original Description",
|
||||||
|
ContentType: models.PlanContentTypeTasks,
|
||||||
|
}
|
||||||
|
getUpdatedErr := errors.New("failed to get updated plan from repository")
|
||||||
|
// 配置模拟仓库行为
|
||||||
|
mockRepo := &MockPlanRepository{
|
||||||
|
// 模拟 GetBasicPlanByID 成功返回现有计划
|
||||||
|
GetBasicPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
||||||
|
return mockPlan, nil
|
||||||
|
},
|
||||||
|
// 模拟 UpdatePlan 成功
|
||||||
|
UpdatePlanFunc: func(plan *models.Plan) error {
|
||||||
|
return nil // 模拟成功更新
|
||||||
|
},
|
||||||
|
// 模拟 GetPlanByID 返回获取失败错误
|
||||||
|
GetPlanByIDFunc: func(id uint) (*models.Plan, error) {
|
||||||
|
return nil, getUpdatedErr // 模拟获取更新后计划失败
|
||||||
|
},
|
||||||
|
}
|
||||||
|
router := setupTestRouter(mockRepo)
|
||||||
|
|
||||||
|
// 准备有效的请求体
|
||||||
|
reqBody := UpdatePlanRequest{
|
||||||
|
Name: "Updated Plan Name",
|
||||||
|
Description: "Updated Description",
|
||||||
|
ExecutionType: models.PlanExecutionTypeAutomatic,
|
||||||
|
ContentType: models.PlanContentTypeTasks,
|
||||||
|
}
|
||||||
|
bodyBytes, _ := json.Marshal(reqBody)
|
||||||
|
|
||||||
|
// 创建 HTTP PUT 请求
|
||||||
|
req, _ := http.NewRequest(http.MethodPut, "/plans/"+strconv.Itoa(int(planID)), bytes.NewBuffer(bodyBytes))
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// TestController_DeletePlan 是 DeletePlan 的单元测试
|
// TestController_DeletePlan 是 DeletePlan 的单元测试
|
||||||
func TestController_DeletePlan(t *testing.T) {
|
func TestController_DeletePlan(t *testing.T) {
|
||||||
t.Run("成功-删除计划", func(t *testing.T) {
|
t.Run("成功-删除计划", func(t *testing.T) {
|
||||||
// Arrange
|
// Arrange (准备阶段)
|
||||||
|
// 模拟仓库行为:DeletePlan 成功
|
||||||
mockRepo := &MockPlanRepository{
|
mockRepo := &MockPlanRepository{
|
||||||
DeletePlanFunc: func(id uint) error {
|
DeletePlanFunc: func(id uint) error {
|
||||||
assert.Equal(t, uint(1), id)
|
assert.Equal(t, uint(1), id)
|
||||||
return nil // Simulate successful deletion
|
return nil // 模拟成功删除
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
router := setupTestRouter(mockRepo)
|
router := setupTestRouter(mockRepo)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
req, _ := http.NewRequest(http.MethodDelete, "/plans/1", nil)
|
req, _ := http.NewRequest(http.MethodDelete, "/plans/1", nil)
|
||||||
|
|
||||||
// Act
|
// Act (执行阶段)
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
// Assert
|
// Assert (断言阶段)
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
var resp controller.Response
|
var resp controller.Response
|
||||||
@@ -392,20 +749,21 @@ func TestController_DeletePlan(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("失败-计划不存在", func(t *testing.T) {
|
t.Run("失败-计划不存在", func(t *testing.T) {
|
||||||
// Arrange
|
// Arrange (准备阶段)
|
||||||
|
// 模拟仓库行为:DeletePlan 返回记录未找到错误
|
||||||
mockRepo := &MockPlanRepository{
|
mockRepo := &MockPlanRepository{
|
||||||
DeletePlanFunc: func(id uint) error {
|
DeletePlanFunc: func(id uint) error {
|
||||||
return gorm.ErrRecordNotFound // Simulate not found
|
return gorm.ErrRecordNotFound // 模拟未找到记录
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
router := setupTestRouter(mockRepo)
|
router := setupTestRouter(mockRepo)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
req, _ := http.NewRequest(http.MethodDelete, "/plans/999", nil)
|
req, _ := http.NewRequest(http.MethodDelete, "/plans/999", nil)
|
||||||
|
|
||||||
// Act
|
// Act (执行阶段)
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
// Assert
|
// Assert (断言阶段)
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
var resp controller.Response
|
var resp controller.Response
|
||||||
@@ -417,16 +775,18 @@ func TestController_DeletePlan(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("失败-无效的ID格式", func(t *testing.T) {
|
t.Run("失败-无效的ID格式", func(t *testing.T) {
|
||||||
// Arrange
|
// Arrange (准备阶段)
|
||||||
mockRepo := &MockPlanRepository{} // No repo call expected
|
// 模拟仓库为空,因为预期不会调用仓库方法
|
||||||
|
mockRepo := &MockPlanRepository{}
|
||||||
router := setupTestRouter(mockRepo)
|
router := setupTestRouter(mockRepo)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
// 创建带有无效ID格式的 HTTP DELETE 请求
|
||||||
req, _ := http.NewRequest(http.MethodDelete, "/plans/abc", nil)
|
req, _ := http.NewRequest(http.MethodDelete, "/plans/abc", nil)
|
||||||
|
|
||||||
// Act
|
// Act (执行阶段)
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
// Assert
|
// Assert (断言阶段)
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
var resp controller.Response
|
var resp controller.Response
|
||||||
@@ -438,21 +798,23 @@ func TestController_DeletePlan(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("失败-仓库层内部错误", func(t *testing.T) {
|
t.Run("失败-仓库层内部错误", func(t *testing.T) {
|
||||||
// Arrange
|
// Arrange (准备阶段)
|
||||||
internalErr := errors.New("something went wrong")
|
internalErr := errors.New("something went wrong")
|
||||||
|
// 模拟仓库行为:DeletePlan 返回内部错误
|
||||||
mockRepo := &MockPlanRepository{
|
mockRepo := &MockPlanRepository{
|
||||||
|
|
||||||
DeletePlanFunc: func(id uint) error {
|
DeletePlanFunc: func(id uint) error {
|
||||||
return internalErr // Simulate internal error
|
return internalErr // 模拟内部错误
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
router := setupTestRouter(mockRepo)
|
router := setupTestRouter(mockRepo)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
req, _ := http.NewRequest(http.MethodDelete, "/plans/1", nil)
|
req, _ := http.NewRequest(http.MethodDelete, "/plans/1", nil)
|
||||||
|
|
||||||
// Act
|
// Act (执行阶段)
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
// Assert
|
// Assert (断言阶段)
|
||||||
assert.Equal(t, http.StatusOK, w.Code)
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
|
||||||
var resp controller.Response
|
var resp controller.Response
|
||||||
|
|||||||
Reference in New Issue
Block a user