Files
junhong_cmp_fiber/tests/unit/enterprise_store_test.go
huang a36e4a79c0 实现用户和组织模型(店铺、企业、个人客户)
核心功能:
- 实现 7 级店铺层级体系(Shop 模型 + 层级校验)
- 实现企业管理模型(Enterprise 模型)
- 实现个人客户管理模型(PersonalCustomer 模型)
- 重构 Account 模型关联关系(基于 EnterpriseID 而非 ParentID)
- 完整的 Store 层和 Service 层实现
- 递归查询下级店铺功能(含 Redis 缓存)
- 全面的单元测试覆盖(Shop/Enterprise/PersonalCustomer Store + Shop Service)

技术要点:
- 显式指定所有 GORM 模型的数据库字段名(column: 标签)
- 统一的字段命名规范(数据库用 snake_case,Go 用 PascalCase)
- 完整的中文字段注释和业务逻辑说明
- 100% 测试覆盖(20+ 测试用例全部通过)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-09 18:02:46 +08:00

408 lines
12 KiB
Go

package unit
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/tests/testutils"
)
// TestEnterpriseStore_Create 测试创建企业
func TestEnterpriseStore_Create(t *testing.T) {
db, redisClient := testutils.SetupTestDB(t)
defer testutils.TeardownTestDB(t, db, redisClient)
store := postgres.NewEnterpriseStore(db, redisClient)
ctx := context.Background()
tests := []struct {
name string
enterprise *model.Enterprise
wantErr bool
}{
{
name: "创建平台直属企业",
enterprise: &model.Enterprise{
EnterpriseName: "测试企业A",
EnterpriseCode: "ENT001",
OwnerShopID: nil, // 平台直属
LegalPerson: "张三",
ContactName: "李四",
ContactPhone: "13800000001",
BusinessLicense: "91110000MA001234",
Province: "北京市",
City: "北京市",
District: "朝阳区",
Address: "朝阳路100号",
Status: constants.StatusEnabled,
},
wantErr: false,
},
{
name: "创建归属店铺的企业",
enterprise: &model.Enterprise{
EnterpriseName: "测试企业B",
EnterpriseCode: "ENT002",
LegalPerson: "王五",
ContactName: "赵六",
ContactPhone: "13800000002",
BusinessLicense: "91110000MA005678",
Status: constants.StatusEnabled,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.enterprise.BaseModel.Creator = 1
tt.enterprise.BaseModel.Updater = 1
err := store.Create(ctx, tt.enterprise)
if tt.wantErr {
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.NotZero(t, tt.enterprise.ID)
assert.NotZero(t, tt.enterprise.CreatedAt)
assert.NotZero(t, tt.enterprise.UpdatedAt)
}
})
}
}
// TestEnterpriseStore_GetByID 测试根据 ID 查询企业
func TestEnterpriseStore_GetByID(t *testing.T) {
db, redisClient := testutils.SetupTestDB(t)
defer testutils.TeardownTestDB(t, db, redisClient)
store := postgres.NewEnterpriseStore(db, redisClient)
ctx := context.Background()
// 创建测试企业
enterprise := &model.Enterprise{
EnterpriseName: "测试企业",
EnterpriseCode: "TEST001",
LegalPerson: "测试法人",
ContactName: "测试联系人",
ContactPhone: "13800000001",
BusinessLicense: "91110000MA001234",
Status: constants.StatusEnabled,
BaseModel: model.BaseModel{
Creator: 1,
Updater: 1,
},
}
err := store.Create(ctx, enterprise)
require.NoError(t, err)
t.Run("查询存在的企业", func(t *testing.T) {
found, err := store.GetByID(ctx, enterprise.ID)
require.NoError(t, err)
assert.Equal(t, enterprise.EnterpriseName, found.EnterpriseName)
assert.Equal(t, enterprise.EnterpriseCode, found.EnterpriseCode)
assert.Equal(t, enterprise.LegalPerson, found.LegalPerson)
})
t.Run("查询不存在的企业", func(t *testing.T) {
_, err := store.GetByID(ctx, 99999)
assert.Error(t, err)
})
}
// TestEnterpriseStore_GetByCode 测试根据企业编号查询
func TestEnterpriseStore_GetByCode(t *testing.T) {
db, redisClient := testutils.SetupTestDB(t)
defer testutils.TeardownTestDB(t, db, redisClient)
store := postgres.NewEnterpriseStore(db, redisClient)
ctx := context.Background()
// 创建测试企业
enterprise := &model.Enterprise{
EnterpriseName: "测试企业",
EnterpriseCode: "UNIQUE001",
LegalPerson: "测试法人",
ContactName: "测试联系人",
ContactPhone: "13800000001",
BusinessLicense: "91110000MA001234",
Status: constants.StatusEnabled,
BaseModel: model.BaseModel{
Creator: 1,
Updater: 1,
},
}
err := store.Create(ctx, enterprise)
require.NoError(t, err)
t.Run("根据企业编号查询", func(t *testing.T) {
found, err := store.GetByCode(ctx, "UNIQUE001")
require.NoError(t, err)
assert.Equal(t, enterprise.ID, found.ID)
assert.Equal(t, enterprise.EnterpriseName, found.EnterpriseName)
})
t.Run("查询不存在的企业编号", func(t *testing.T) {
_, err := store.GetByCode(ctx, "NONEXISTENT")
assert.Error(t, err)
})
}
// TestEnterpriseStore_Update 测试更新企业
func TestEnterpriseStore_Update(t *testing.T) {
db, redisClient := testutils.SetupTestDB(t)
defer testutils.TeardownTestDB(t, db, redisClient)
store := postgres.NewEnterpriseStore(db, redisClient)
ctx := context.Background()
// 创建测试企业
enterprise := &model.Enterprise{
EnterpriseName: "原始企业名称",
EnterpriseCode: "UPDATE001",
LegalPerson: "原法人",
ContactName: "原联系人",
ContactPhone: "13800000001",
BusinessLicense: "91110000MA001234",
Status: constants.StatusEnabled,
BaseModel: model.BaseModel{
Creator: 1,
Updater: 1,
},
}
err := store.Create(ctx, enterprise)
require.NoError(t, err)
t.Run("更新企业信息", func(t *testing.T) {
enterprise.EnterpriseName = "更新后的企业名称"
enterprise.LegalPerson = "新法人"
enterprise.ContactName = "新联系人"
enterprise.ContactPhone = "13900000001"
enterprise.Updater = 2
err := store.Update(ctx, enterprise)
require.NoError(t, err)
// 验证更新
found, err := store.GetByID(ctx, enterprise.ID)
require.NoError(t, err)
assert.Equal(t, "更新后的企业名称", found.EnterpriseName)
assert.Equal(t, "新法人", found.LegalPerson)
assert.Equal(t, "新联系人", found.ContactName)
assert.Equal(t, "13900000001", found.ContactPhone)
assert.Equal(t, uint(2), found.Updater)
})
t.Run("更新企业状态", func(t *testing.T) {
enterprise.Status = constants.StatusDisabled
err := store.Update(ctx, enterprise)
require.NoError(t, err)
found, err := store.GetByID(ctx, enterprise.ID)
require.NoError(t, err)
assert.Equal(t, constants.StatusDisabled, found.Status)
})
}
// TestEnterpriseStore_Delete 测试软删除企业
func TestEnterpriseStore_Delete(t *testing.T) {
db, redisClient := testutils.SetupTestDB(t)
defer testutils.TeardownTestDB(t, db, redisClient)
store := postgres.NewEnterpriseStore(db, redisClient)
ctx := context.Background()
// 创建测试企业
enterprise := &model.Enterprise{
EnterpriseName: "待删除企业",
EnterpriseCode: "DELETE001",
LegalPerson: "测试",
ContactName: "测试",
ContactPhone: "13800000001",
BusinessLicense: "91110000MA001234",
Status: constants.StatusEnabled,
BaseModel: model.BaseModel{
Creator: 1,
Updater: 1,
},
}
err := store.Create(ctx, enterprise)
require.NoError(t, err)
t.Run("软删除企业", func(t *testing.T) {
err := store.Delete(ctx, enterprise.ID)
require.NoError(t, err)
// 验证已被软删除
_, err = store.GetByID(ctx, enterprise.ID)
assert.Error(t, err)
})
}
// TestEnterpriseStore_List 测试查询企业列表
func TestEnterpriseStore_List(t *testing.T) {
db, redisClient := testutils.SetupTestDB(t)
defer testutils.TeardownTestDB(t, db, redisClient)
store := postgres.NewEnterpriseStore(db, redisClient)
ctx := context.Background()
// 创建多个测试企业
for i := 1; i <= 5; i++ {
enterprise := &model.Enterprise{
EnterpriseName: testutils.GenerateUsername("测试企业", i),
EnterpriseCode: testutils.GenerateUsername("ENT", i),
LegalPerson: "测试法人",
ContactName: "测试联系人",
ContactPhone: testutils.GeneratePhone("138", i),
BusinessLicense: testutils.GenerateUsername("LICENSE", i),
Status: constants.StatusEnabled,
BaseModel: model.BaseModel{
Creator: 1,
Updater: 1,
},
}
err := store.Create(ctx, enterprise)
require.NoError(t, err)
}
t.Run("分页查询", func(t *testing.T) {
enterprises, total, err := store.List(ctx, nil, nil)
require.NoError(t, err)
assert.GreaterOrEqual(t, len(enterprises), 5)
assert.GreaterOrEqual(t, total, int64(5))
})
t.Run("带过滤条件查询", func(t *testing.T) {
filters := map[string]interface{}{
"status": constants.StatusEnabled,
}
enterprises, _, err := store.List(ctx, nil, filters)
require.NoError(t, err)
for _, ent := range enterprises {
assert.Equal(t, constants.StatusEnabled, ent.Status)
}
})
}
// TestEnterpriseStore_GetByOwnerShopID 测试根据归属店铺查询企业
func TestEnterpriseStore_GetByOwnerShopID(t *testing.T) {
db, redisClient := testutils.SetupTestDB(t)
defer testutils.TeardownTestDB(t, db, redisClient)
store := postgres.NewEnterpriseStore(db, redisClient)
ctx := context.Background()
shopID1 := uint(100)
shopID2 := uint(200)
// 创建归属不同店铺的企业
for i := 1; i <= 3; i++ {
enterprise := &model.Enterprise{
EnterpriseName: testutils.GenerateUsername("店铺100企业", i),
EnterpriseCode: testutils.GenerateUsername("SHOP100_ENT", i),
OwnerShopID: &shopID1,
LegalPerson: "测试法人",
ContactName: "测试联系人",
ContactPhone: testutils.GeneratePhone("138", i),
BusinessLicense: testutils.GenerateUsername("LICENSE", i),
Status: constants.StatusEnabled,
BaseModel: model.BaseModel{
Creator: 1,
Updater: 1,
},
}
err := store.Create(ctx, enterprise)
require.NoError(t, err)
}
for i := 1; i <= 2; i++ {
enterprise := &model.Enterprise{
EnterpriseName: testutils.GenerateUsername("店铺200企业", i),
EnterpriseCode: testutils.GenerateUsername("SHOP200_ENT", i),
OwnerShopID: &shopID2,
LegalPerson: "测试法人",
ContactName: "测试联系人",
ContactPhone: testutils.GeneratePhone("139", i),
BusinessLicense: testutils.GenerateUsername("LICENSE2", i),
Status: constants.StatusEnabled,
BaseModel: model.BaseModel{
Creator: 1,
Updater: 1,
},
}
err := store.Create(ctx, enterprise)
require.NoError(t, err)
}
t.Run("查询店铺100的企业", func(t *testing.T) {
enterprises, err := store.GetByOwnerShopID(ctx, shopID1)
require.NoError(t, err)
assert.Len(t, enterprises, 3)
for _, ent := range enterprises {
assert.NotNil(t, ent.OwnerShopID)
assert.Equal(t, shopID1, *ent.OwnerShopID)
}
})
t.Run("查询店铺200的企业", func(t *testing.T) {
enterprises, err := store.GetByOwnerShopID(ctx, shopID2)
require.NoError(t, err)
assert.Len(t, enterprises, 2)
for _, ent := range enterprises {
assert.NotNil(t, ent.OwnerShopID)
assert.Equal(t, shopID2, *ent.OwnerShopID)
}
})
}
// TestEnterpriseStore_UniqueConstraints 测试唯一约束
func TestEnterpriseStore_UniqueConstraints(t *testing.T) {
db, redisClient := testutils.SetupTestDB(t)
defer testutils.TeardownTestDB(t, db, redisClient)
store := postgres.NewEnterpriseStore(db, redisClient)
ctx := context.Background()
// 创建测试企业
enterprise := &model.Enterprise{
EnterpriseName: "唯一测试企业",
EnterpriseCode: "UNIQUE_CODE",
LegalPerson: "测试",
ContactName: "测试",
ContactPhone: "13800000001",
BusinessLicense: "91110000MA001234",
Status: constants.StatusEnabled,
BaseModel: model.BaseModel{
Creator: 1,
Updater: 1,
},
}
err := store.Create(ctx, enterprise)
require.NoError(t, err)
t.Run("重复企业编号应失败", func(t *testing.T) {
duplicate := &model.Enterprise{
EnterpriseName: "另一个企业",
EnterpriseCode: "UNIQUE_CODE", // 重复
LegalPerson: "测试",
ContactName: "测试",
ContactPhone: "13800000002",
BusinessLicense: "91110000MA005678",
Status: constants.StatusEnabled,
BaseModel: model.BaseModel{
Creator: 1,
Updater: 1,
},
}
err := store.Create(ctx, duplicate)
assert.Error(t, err)
})
}