查看计划简单信息和单测
This commit is contained in:
@@ -14,11 +14,11 @@ import (
|
|||||||
func setupTestDB(t *testing.T) *gorm.DB {
|
func setupTestDB(t *testing.T) *gorm.DB {
|
||||||
// "file::memory:?cache=shared" 是 GORM 连接内存 SQLite 的标准方式,确保在同一测试中的不同连接可以访问相同的数据。
|
// "file::memory:?cache=shared" 是 GORM 连接内存 SQLite 的标准方式,确保在同一测试中的不同连接可以访问相同的数据。
|
||||||
db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
|
db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
|
||||||
assert.NoError(t, err, "连接内存数据库不应出错")
|
assert.NoError(t, err, "连接内存数据库时发生错误")
|
||||||
|
|
||||||
// 自动迁移所有需要的表结构
|
// 自动迁移所有需要的表结构
|
||||||
err = db.AutoMigrate(&models.User{}, &models.Device{})
|
err = db.AutoMigrate(&models.User{}, &models.Device{}, &models.SubPlan{}, &models.Task{}, &models.Plan{})
|
||||||
assert.NoError(t, err, "数据库迁移不应出错")
|
assert.NoError(t, err, "数据库迁移时发生错误")
|
||||||
|
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|||||||
49
internal/infra/repository/plan_repository.go
Normal file
49
internal/infra/repository/plan_repository.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PlanRepository 定义了与计划模型相关的数据库操作接口
|
||||||
|
// 这是为了让业务逻辑层依赖于抽象,而不是具体的数据库实现
|
||||||
|
type PlanRepository interface {
|
||||||
|
// ListBasicPlans 获取所有计划的基本信息,不包含子计划和任务详情
|
||||||
|
ListBasicPlans() ([]models.Plan, error)
|
||||||
|
// GetBasicPlanByID 根据ID获取计划的基本信息,不包含子计划和任务详情
|
||||||
|
GetBasicPlanByID(id uint) (*models.Plan, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// gormPlanRepository 是 PlanRepository 的 GORM 实现
|
||||||
|
type gormPlanRepository struct {
|
||||||
|
db *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGormPlanRepository 创建一个新的 PlanRepository GORM 实现实例
|
||||||
|
func NewGormPlanRepository(db *gorm.DB) PlanRepository {
|
||||||
|
return &gormPlanRepository{
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListBasicPlans 获取所有计划的基本信息,不包含子计划和任务详情
|
||||||
|
func (r *gormPlanRepository) ListBasicPlans() ([]models.Plan, error) {
|
||||||
|
var plans []models.Plan
|
||||||
|
// GORM 默认不会加载关联,除非使用 Preload,所以直接 Find 即可满足要求
|
||||||
|
result := r.db.Find(&plans)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
return plans, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBasicPlanByID 根据ID获取计划的基本信息,不包含子计划和任务详情
|
||||||
|
func (r *gormPlanRepository) GetBasicPlanByID(id uint) (*models.Plan, error) {
|
||||||
|
var plan models.Plan
|
||||||
|
// GORM 默认不会加载关联,除非使用 Preload,所以直接 First 即可满足要求
|
||||||
|
result := r.db.First(&plan, id)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
return &plan, nil
|
||||||
|
}
|
||||||
136
internal/infra/repository/plan_repository_test.go
Normal file
136
internal/infra/repository/plan_repository_test.go
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
package repository_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
||||||
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// createTestPlan 是一个辅助函数,用于创建测试计划。
|
||||||
|
func createTestPlan(name, description string, execType models.PlanExecutionType, contentType models.PlanContentType) models.Plan {
|
||||||
|
return models.Plan{
|
||||||
|
Name: name,
|
||||||
|
Description: description,
|
||||||
|
ExecutionType: execType,
|
||||||
|
ContentType: contentType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestListBasicPlans 测试 ListBasicPlans 方法,确保它能正确返回所有计划的基本信息。
|
||||||
|
func TestListBasicPlans(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
setupPlans []models.Plan
|
||||||
|
expectedCount int
|
||||||
|
expectedError error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "数据库中没有计划",
|
||||||
|
setupPlans: []models.Plan{},
|
||||||
|
expectedCount: 0,
|
||||||
|
expectedError: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "数据库中有多个计划",
|
||||||
|
setupPlans: []models.Plan{
|
||||||
|
createTestPlan("计划 A", "描述 A", models.PlanExecutionTypeAutomatic, models.PlanContentTypeTasks),
|
||||||
|
createTestPlan("计划 B", "描述 B", models.PlanExecutionTypeManual, models.PlanContentTypeSubPlans),
|
||||||
|
},
|
||||||
|
expectedCount: 2,
|
||||||
|
expectedError: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db := setupTestDB(t)
|
||||||
|
repo := repository.NewGormPlanRepository(db)
|
||||||
|
|
||||||
|
for i := range tt.setupPlans {
|
||||||
|
err := db.Create(&tt.setupPlans[i]).Error
|
||||||
|
assert.NoError(t, err, "插入设置计划失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
plans, err := repo.ListBasicPlans()
|
||||||
|
|
||||||
|
if tt.expectedError != nil {
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.True(t, errors.Is(err, tt.expectedError))
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, plans, tt.expectedCount)
|
||||||
|
if tt.expectedCount > 0 {
|
||||||
|
// 验证返回的计划是否包含预期的ID
|
||||||
|
var actualIDs []uint
|
||||||
|
for _, p := range plans {
|
||||||
|
actualIDs = append(actualIDs, p.ID)
|
||||||
|
assert.Empty(t, p.SubPlans, "ListBasicPlans 不应加载子计划")
|
||||||
|
assert.Empty(t, p.Tasks, "ListBasicPlans 不应加载任务")
|
||||||
|
}
|
||||||
|
for _, setupPlan := range tt.setupPlans {
|
||||||
|
assert.Contains(t, actualIDs, setupPlan.ID, "返回的计划应包含设置计划的ID")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestGetBasicPlanByID 测试 GetBasicPlanByID 方法,确保它能根据ID正确返回计划的基本信息。
|
||||||
|
func TestGetBasicPlanByID(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
setupPlan models.Plan
|
||||||
|
idToFetch uint
|
||||||
|
expectFound bool
|
||||||
|
expectedError error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "通过ID找到计划",
|
||||||
|
setupPlan: createTestPlan("计划 C", "描述 C", models.PlanExecutionTypeAutomatic, models.PlanContentTypeTasks),
|
||||||
|
idToFetch: 0, // 创建后设置
|
||||||
|
expectFound: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "通过ID未找到计划",
|
||||||
|
setupPlan: models.Plan{}, // 此情况下无需设置计划
|
||||||
|
idToFetch: 999,
|
||||||
|
expectFound: false,
|
||||||
|
expectedError: gorm.ErrRecordNotFound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db := setupTestDB(t)
|
||||||
|
repo := repository.NewGormPlanRepository(db)
|
||||||
|
|
||||||
|
if tt.setupPlan.Name != "" { // 仅在有效设置时创建计划
|
||||||
|
err := db.Create(&tt.setupPlan).Error
|
||||||
|
assert.NoError(t, err, "插入设置计划失败")
|
||||||
|
tt.idToFetch = tt.setupPlan.ID // 使用数据库生成的ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchedPlan, err := repo.GetBasicPlanByID(tt.idToFetch)
|
||||||
|
|
||||||
|
if tt.expectedError != nil {
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.True(t, errors.Is(err, tt.expectedError), "预期错误类型不匹配")
|
||||||
|
assert.Nil(t, fetchedPlan)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, fetchedPlan)
|
||||||
|
assert.Equal(t, tt.setupPlan.Name, fetchedPlan.Name)
|
||||||
|
assert.Equal(t, tt.setupPlan.Description, fetchedPlan.Description)
|
||||||
|
assert.Equal(t, tt.setupPlan.ExecutionType, fetchedPlan.ExecutionType)
|
||||||
|
assert.Equal(t, tt.setupPlan.ContentType, fetchedPlan.ContentType)
|
||||||
|
assert.Empty(t, fetchedPlan.SubPlans, "GetBasicPlanByID 不应加载子计划")
|
||||||
|
assert.Empty(t, fetchedPlan.Tasks, "GetBasicPlanByID 不应加载任务")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user