app-cloudep-product-service/pkg/usecase/product_item_test.go

311 lines
9.2 KiB
Go

package usecase
import (
"context"
"errors"
"testing"
"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"
"github.com/shopspring/decimal"
"github.com/stretchr/testify/assert"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.uber.org/mock/gomock"
)
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, []string{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, []string{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")
})
}