feat: usecast test

This commit is contained in:
王性驊 2025-04-05 22:29:53 +08:00
parent 52905207c6
commit c4617956e5
3 changed files with 554 additions and 2 deletions

View File

@ -0,0 +1,309 @@
package usecase
import (
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/entity"
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/product"
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/repository"
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/usecase"
mockRepository "code.30cm.net/digimon/app-cloudep-product-service/pkg/mock/repository"
"context"
"errors"
"github.com/shopspring/decimal"
"github.com/stretchr/testify/assert"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.uber.org/mock/gomock"
"testing"
)
func TestProductItemUseCase_Create(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockProductItemRepo := mockRepository.NewMockProductItemRepository(mockCtrl)
useCase := MustProductItemUseCase(ProductItemUseCaseParam{
ProductItems: mockProductItemRepo,
})
ctx := context.Background()
input := &usecase.ProductItems{
ReferenceID: "p-id",
Name: "Item A",
Description: "desc",
ShortDescription: "short",
IsUnLimit: false,
IsFree: false,
Stock: 100,
Price: "123.45",
SKU: "SKU001",
TimeSeries: product.TimeSeriesTenMinutes,
Status: product.StatusUnderReview,
}
t.Run("建立成功", func(t *testing.T) {
mockProductItemRepo.EXPECT().Insert(ctx, gomock.Any()).Return(nil)
err := useCase.Create(ctx, input)
assert.NoError(t, err)
})
t.Run("轉換失敗 - 價格格式錯誤", func(t *testing.T) {
badInput := *input
badInput.Price = "invalid-price"
err := useCase.Create(ctx, &badInput)
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to change use case into entity")
})
t.Run("建立失敗 - DB 錯誤", func(t *testing.T) {
mockProductItemRepo.EXPECT().Insert(ctx, gomock.Any()).Return(errors.New("db error"))
err := useCase.Create(ctx, input)
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to insert product item")
})
}
func TestProductItemUseCase_Get(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockProductItemRepo := mockRepository.NewMockProductItemRepository(mockCtrl)
useCase := MustProductItemUseCase(ProductItemUseCaseParam{
ProductItems: mockProductItemRepo,
})
ctx := context.Background()
id := primitive.NewObjectID().Hex()
ent := &entity.ProductItems{
ID: primitive.NewObjectID(),
ReferenceID: "ref-id",
Name: "Item A",
Description: "desc",
ShortDescription: "short",
IsUnLimit: true,
IsFree: false,
Stock: 50,
Price: decimal.NewFromInt(999),
SKU: "sku-01",
TimeSeries: product.TimeSeriesHalfHour,
Status: product.StatusUnderReview,
SalesCount: 10,
UpdatedAt: 1700000000,
CreatedAt: 1600000000,
}
t.Run("查詢成功", func(t *testing.T) {
mockProductItemRepo.EXPECT().FindByID(ctx, id).Return(ent, nil)
resp, err := useCase.Get(ctx, id)
assert.NoError(t, err)
assert.Equal(t, ent.Name, resp.Name)
assert.Equal(t, ent.Price.String(), resp.Price)
})
t.Run("查詢失敗 - DB 錯誤", func(t *testing.T) {
mockProductItemRepo.EXPECT().FindByID(ctx, id).Return(nil, errors.New("db error"))
resp, err := useCase.Get(ctx, id)
assert.Error(t, err)
assert.Nil(t, resp)
assert.Contains(t, err.Error(), "failed to create product items")
})
}
func TestProductItemUseCase_Update(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockRepo := mockRepository.NewMockProductItemRepository(mockCtrl)
useCase := MustProductItemUseCase(ProductItemUseCaseParam{
ProductItems: mockRepo,
})
ctx := context.Background()
id := primitive.NewObjectID().Hex()
t.Run("更新成功", func(t *testing.T) {
stock := uint64(100)
price := "123.45"
param := &usecase.UpdateProductItems{
Name: ptr("New Name"),
Stock: &stock,
Price: &price,
IsFree: ptr(true),
}
mockRepo.EXPECT().Update(ctx, id, gomock.Any()).Return(nil)
err := useCase.Update(ctx, id, param)
assert.NoError(t, err)
})
t.Run("更新失敗 - 價格格式錯誤", func(t *testing.T) {
price := "invalid-price"
param := &usecase.UpdateProductItems{
Price: &price,
}
err := useCase.Update(ctx, id, param)
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to convert price")
})
t.Run("更新失敗 - DB 錯誤", func(t *testing.T) {
price := "456.78"
param := &usecase.UpdateProductItems{
Price: &price,
}
mockRepo.EXPECT().Update(ctx, id, gomock.Any()).Return(errors.New("db error"))
err := useCase.Update(ctx, id, param)
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to update product item")
})
}
func TestProductItemUseCase_IncSalesCount(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockItemRepo := mockRepository.NewMockProductItemRepository(mockCtrl)
useCase := MustProductItemUseCase(ProductItemUseCaseParam{
ProductItems: mockItemRepo,
})
ctx := context.Background()
id := "item-123"
saleCount := uint64(10)
t.Run("成功增加銷售數量", func(t *testing.T) {
mockItemRepo.EXPECT().IncSalesCount(ctx, id, int64(saleCount)).Return(nil)
err := useCase.IncSalesCount(ctx, id, saleCount)
assert.NoError(t, err)
})
t.Run("資料庫錯誤", func(t *testing.T) {
mockItemRepo.EXPECT().IncSalesCount(ctx, id, int64(saleCount)).Return(errors.New("db error"))
err := useCase.IncSalesCount(ctx, id, saleCount)
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to insert product item")
})
}
func TestProductItemUseCase_DecSalesCount(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockItemRepo := mockRepository.NewMockProductItemRepository(mockCtrl)
useCase := MustProductItemUseCase(ProductItemUseCaseParam{
ProductItems: mockItemRepo,
})
ctx := context.Background()
id := "item-123"
saleCount := uint64(5)
t.Run("成功減少銷售數量", func(t *testing.T) {
mockItemRepo.EXPECT().DecSalesCount(ctx, id, int64(saleCount)).Return(nil)
err := useCase.DecSalesCount(ctx, id, saleCount)
assert.NoError(t, err)
})
t.Run("資料庫錯誤", func(t *testing.T) {
mockItemRepo.EXPECT().DecSalesCount(ctx, id, int64(saleCount)).Return(errors.New("db error"))
err := useCase.DecSalesCount(ctx, id, saleCount)
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to Dec product item")
})
}
func TestProductItemUseCase_Delete(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockItemRepo := mockRepository.NewMockProductItemRepository(mockCtrl)
useCase := MustProductItemUseCase(ProductItemUseCaseParam{
ProductItems: mockItemRepo,
})
ctx := context.Background()
id := "item-456"
t.Run("刪除成功", func(t *testing.T) {
mockItemRepo.EXPECT().Delete(ctx, []string{id}).Return(nil)
err := useCase.Delete(ctx, id)
assert.NoError(t, err)
})
t.Run("資料庫錯誤", func(t *testing.T) {
mockItemRepo.EXPECT().Delete(ctx, []string{id}).Return(errors.New("db error"))
err := useCase.Delete(ctx, id)
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to delete product item")
})
}
func TestProductItemUseCase_List(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockItemRepo := mockRepository.NewMockProductItemRepository(mockCtrl)
useCase := MustProductItemUseCase(ProductItemUseCaseParam{
ProductItems: mockItemRepo,
})
ctx := context.Background()
refID := "ref-123"
params := usecase.QueryProductItemParam{
PageSize: 10,
PageIndex: 1,
ReferenceID: &refID,
}
repoParams := repository.ProductItemQueryParams{
PageSize: 10,
PageIndex: 1,
ReferenceID: &refID,
}
t.Run("成功列出項目", func(t *testing.T) {
mockItemRepo.EXPECT().ListProductItem(ctx, repoParams).Return([]entity.ProductItems{{ReferenceID: refID, Name: "Item A"}}, int64(1), nil)
items, total, err := useCase.List(ctx, params)
assert.NoError(t, err)
assert.Equal(t, int64(1), total)
assert.Equal(t, 1, len(items))
})
t.Run("查詢失敗 - DB 錯誤", func(t *testing.T) {
mockItemRepo.EXPECT().ListProductItem(ctx, repoParams).Return(nil, int64(0), errors.New("db error"))
items, total, err := useCase.List(ctx, params)
assert.Error(t, err)
assert.Nil(t, items)
assert.Equal(t, int64(0), total)
assert.Contains(t, err.Error(), "failed to list product item")
})
}
func TestProductItemUseCase_UpdateStatus(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockRepo := mockRepository.NewMockProductItemRepository(mockCtrl)
useCase := MustProductItemUseCase(ProductItemUseCaseParam{
ProductItems: mockRepo,
})
ctx := context.Background()
id := primitive.NewObjectID().Hex()
status := product.StatusUnderReview
t.Run("更新成功", func(t *testing.T) {
mockRepo.EXPECT().UpdateStatus(ctx, id, status).Return(nil)
err := useCase.UpdateStatus(ctx, id, status)
assert.NoError(t, err)
})
t.Run("更新失敗 - 資料庫錯誤", func(t *testing.T) {
mockRepo.EXPECT().UpdateStatus(ctx, id, status).Return(errors.New("db error"))
err := useCase.UpdateStatus(ctx, id, status)
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to update product item status")
})
}

View File

@ -4,14 +4,13 @@ import (
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/entity"
repo "code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/repository"
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/usecase"
"code.30cm.net/digimon/app-cloudep-product-service/pkg/repository"
"code.30cm.net/digimon/library-go/errs"
"context"
"github.com/zeromicro/go-zero/core/logx"
)
type TagsUseCaseParam struct {
TagsRepo repository.TagsRepository
TagsRepo repo.TagRepo
}
type TagsUseCase struct {

244
pkg/usecase/tags_test.go Normal file
View File

@ -0,0 +1,244 @@
package usecase
import (
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/entity"
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/product"
repo "code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/repository"
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/usecase"
mockRepository "code.30cm.net/digimon/app-cloudep-product-service/pkg/mock/repository"
"context"
"errors"
"github.com/stretchr/testify/assert"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.uber.org/mock/gomock"
"testing"
)
func TestTagsUseCase_Create(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockTagsRepo := mockRepository.NewMockTagRepo(mockCtrl)
useCase := MustTagsUseCase(TagsUseCaseParam{
TagsRepo: mockTagsRepo,
})
ctx := context.Background()
input := &entity.Tags{
Name: "Test Tag",
Types: product.ItemTypeProduct,
ShowType: product.ShowTypeNormal,
}
t.Run("建立成功", func(t *testing.T) {
mockTagsRepo.EXPECT().Create(ctx, input).Return(nil)
err := useCase.Create(ctx, input)
assert.NoError(t, err)
})
t.Run("建立失敗 - DB 錯誤", func(t *testing.T) {
mockTagsRepo.EXPECT().Create(ctx, input).Return(errors.New("db error"))
err := useCase.Create(ctx, input)
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to create tags")
})
}
func TestTagsUseCase_GetByID(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockTagsRepo := mockRepository.NewMockTagRepo(mockCtrl)
useCase := MustTagsUseCase(TagsUseCaseParam{
TagsRepo: mockTagsRepo,
})
ctx := context.Background()
id := primitive.NewObjectID().Hex()
t.Run("查詢成功", func(t *testing.T) {
expected := &entity.Tags{
ID: primitive.NewObjectID(),
Name: "Test Tag",
Types: product.ItemTypeProduct,
ShowType: product.ShowTypeNormal,
}
mockTagsRepo.EXPECT().GetByID(ctx, id).Return(expected, nil)
tag, err := useCase.GetByID(ctx, id)
assert.NoError(t, err)
assert.Equal(t, expected, tag)
})
t.Run("查詢失敗 - DB 錯誤", func(t *testing.T) {
mockTagsRepo.EXPECT().GetByID(ctx, id).Return(nil, errors.New("db error"))
tag, err := useCase.GetByID(ctx, id)
assert.Error(t, err)
assert.Nil(t, tag)
assert.Contains(t, err.Error(), "failed to get tags")
})
}
func TestTagsUseCase_GetByIDs(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockTagsRepo := mockRepository.NewMockTagRepo(mockCtrl)
useCase := MustTagsUseCase(TagsUseCaseParam{
TagsRepo: mockTagsRepo,
})
ctx := context.Background()
ids := []string{"id1", "id2"}
t.Run("查詢成功", func(t *testing.T) {
expected := []*entity.Tags{
{Name: "Tag1", Types: product.ItemTypeProduct, ShowType: product.ShowTypeNormal},
{Name: "Tag2", Types: product.ItemTypeProduct, ShowType: product.ShowTypeNormal},
}
mockTagsRepo.EXPECT().GetByIDs(ctx, ids).Return(expected, nil)
tags, err := useCase.GetByIDs(ctx, ids)
assert.NoError(t, err)
assert.Equal(t, expected, tags)
})
t.Run("查詢失敗 - DB 錯誤", func(t *testing.T) {
mockTagsRepo.EXPECT().GetByIDs(ctx, ids).Return(nil, errors.New("db error"))
tags, err := useCase.GetByIDs(ctx, ids)
assert.Error(t, err)
assert.Nil(t, tags)
assert.Contains(t, err.Error(), "failed to get tags")
})
}
func TestTagsUseCase_Delete(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockTagsRepo := mockRepository.NewMockTagRepo(mockCtrl)
useCase := MustTagsUseCase(TagsUseCaseParam{
TagsRepo: mockTagsRepo,
})
ctx := context.Background()
id := primitive.NewObjectID().Hex()
t.Run("刪除成功", func(t *testing.T) {
mockTagsRepo.EXPECT().Delete(ctx, id).Return(nil)
err := useCase.Delete(ctx, id)
assert.NoError(t, err)
})
t.Run("刪除失敗 - DB 錯誤", func(t *testing.T) {
mockTagsRepo.EXPECT().Delete(ctx, id).Return(errors.New("db error"))
err := useCase.Delete(ctx, id)
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to delete tags")
})
}
func TestTagsUseCase_List(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockTagsRepo := mockRepository.NewMockTagRepo(mockCtrl)
useCase := MustTagsUseCase(TagsUseCaseParam{
TagsRepo: mockTagsRepo,
})
ctx := context.Background()
params := usecase.TagQueryParams{
PageSize: 10,
PageIndex: 1,
Types: ptr(product.ItemTypeProduct),
Name: ptr("AI"),
ShowType: ptr(product.ShowTypeNormal),
}
t.Run("查詢成功", func(t *testing.T) {
expected := []*entity.Tags{
{Name: "AI", Types: product.ItemTypeProduct, ShowType: product.ShowTypeNormal},
}
mockTagsRepo.EXPECT().List(ctx, repo.TagQueryParams{
PageSize: 10,
PageIndex: 1,
Types: ptr(product.ItemTypeProduct),
Name: ptr("AI"),
ShowType: ptr(product.ShowTypeNormal),
}).Return(expected, int64(1), nil)
res, total, err := useCase.List(ctx, params)
assert.NoError(t, err)
assert.Equal(t, expected, res)
assert.Equal(t, int64(1), total)
})
t.Run("查詢失敗 - DB 錯誤", func(t *testing.T) {
dbErr := errors.New("db error")
mockTagsRepo.EXPECT().List(ctx, repo.TagQueryParams{
PageSize: 10,
PageIndex: 1,
Types: ptr(product.ItemTypeProduct),
Name: ptr("AI"),
ShowType: ptr(product.ShowTypeNormal),
}).Return(nil, int64(0), dbErr)
res, total, err := useCase.List(ctx, params)
assert.Error(t, err)
assert.Nil(t, res)
assert.Equal(t, int64(0), total)
assert.Contains(t, err.Error(), "failed to list tags")
})
}
func TestTagsUseCase_Update(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockTagsRepo := mockRepository.NewMockTagRepo(mockCtrl)
useCase := MustTagsUseCase(TagsUseCaseParam{
TagsRepo: mockTagsRepo,
})
ctx := context.Background()
id := primitive.NewObjectID().Hex()
tagParams := usecase.TagModifyParams{
Name: ptr("New Name"),
Types: ptr(product.ItemTypeProduct),
ShowType: ptr(product.ShowTypeNormal),
Cover: ptr("https://image.jpg"),
}
t.Run("更新成功", func(t *testing.T) {
mockTagsRepo.EXPECT().Update(ctx, id, repo.TagModifyParams{
Name: tagParams.Name,
Types: tagParams.Types,
ShowType: tagParams.ShowType,
Cover: tagParams.Cover,
}).Return(nil)
err := useCase.Update(ctx, id, tagParams)
assert.NoError(t, err)
})
t.Run("更新失敗 - DB 錯誤", func(t *testing.T) {
dbErr := errors.New("db error")
mockTagsRepo.EXPECT().Update(ctx, id, repo.TagModifyParams{
Name: tagParams.Name,
Types: tagParams.Types,
ShowType: tagParams.ShowType,
Cover: tagParams.Cover,
}).Return(dbErr)
err := useCase.Update(ctx, id, tagParams)
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to update tags")
})
}