test(pipeline): 更新人脸识别流水线集成测试配置

- 替换 Spring Boot 测试注解为 Mockito 扩展
- 添加所有流水线阶段的 Mock 对象注入
- 更新自动匹配旧版本流水线的阶段数量断言
- 在多个阶段测试中添加 FaceStatusManager 的 Mock 验证
- 修改价格计算服务升级检查测试的业务逻辑验证
- 修复产品类型能力服务中的类别常量值
This commit is contained in:
2026-01-27 21:28:09 +08:00
parent 0ed12af8c9
commit 1c0a506238
9 changed files with 175 additions and 67 deletions

View File

@@ -1,13 +1,35 @@
package com.ycwl.basic.face.pipeline.integration;
import com.ycwl.basic.face.pipeline.core.FaceMatchingContext;
import com.ycwl.basic.pipeline.core.Pipeline;
import com.ycwl.basic.face.pipeline.enums.FaceMatchingScene;
import com.ycwl.basic.face.pipeline.factory.FaceMatchingPipelineFactory;
import com.ycwl.basic.face.pipeline.stages.BuildSourceRelationStage;
import com.ycwl.basic.face.pipeline.stages.CreateTaskStage;
import com.ycwl.basic.face.pipeline.stages.CustomFaceSearchStage;
import com.ycwl.basic.face.pipeline.stages.DeleteOldRelationsStage;
import com.ycwl.basic.face.pipeline.stages.FaceRecognitionStage;
import com.ycwl.basic.face.pipeline.stages.FaceRecoveryStage;
import com.ycwl.basic.face.pipeline.stages.FilterByDevicePhotoLimitStage;
import com.ycwl.basic.face.pipeline.stages.FilterByTimeRangeStage;
import com.ycwl.basic.face.pipeline.stages.GeneratePuzzleStage;
import com.ycwl.basic.face.pipeline.stages.HandleVideoRecreationStage;
import com.ycwl.basic.face.pipeline.stages.LoadFaceSamplesStage;
import com.ycwl.basic.face.pipeline.stages.LoadMatchedSamplesStage;
import com.ycwl.basic.face.pipeline.stages.PersistRelationsStage;
import com.ycwl.basic.face.pipeline.stages.PrepareContextStage;
import com.ycwl.basic.face.pipeline.stages.ProcessBuyStatusStage;
import com.ycwl.basic.face.pipeline.stages.ProcessFreeSourceStage;
import com.ycwl.basic.face.pipeline.stages.RecordCustomMatchMetricsStage;
import com.ycwl.basic.face.pipeline.stages.RecordMetricsStage;
import com.ycwl.basic.face.pipeline.stages.SetTaskStatusStage;
import com.ycwl.basic.face.pipeline.stages.UpdateFaceResultStage;
import com.ycwl.basic.pipeline.core.Pipeline;
import com.ycwl.basic.service.pc.helper.ScenicConfigFacade;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Arrays;
@@ -17,13 +39,55 @@ import static org.junit.jupiter.api.Assertions.*;
* Pipeline集成测试
* 测试Pipeline的完整流程和Stage协作
*/
@SpringBootTest
@ActiveProfiles("test")
@ExtendWith(MockitoExtension.class)
class FaceMatchingPipelineIntegrationTest {
@Autowired
@InjectMocks
private FaceMatchingPipelineFactory pipelineFactory;
@Mock
private PrepareContextStage prepareContextStage;
@Mock
private RecordMetricsStage recordMetricsStage;
@Mock
private FaceRecognitionStage faceRecognitionStage;
@Mock
private FaceRecoveryStage faceRecoveryStage;
@Mock
private UpdateFaceResultStage updateFaceResultStage;
@Mock
private BuildSourceRelationStage buildSourceRelationStage;
@Mock
private ProcessFreeSourceStage processFreeSourceStage;
@Mock
private ProcessBuyStatusStage processBuyStatusStage;
@Mock
private HandleVideoRecreationStage handleVideoRecreationStage;
@Mock
private PersistRelationsStage persistRelationsStage;
@Mock
private CreateTaskStage createTaskStage;
@Mock
private SetTaskStatusStage setTaskStatusStage;
@Mock
private GeneratePuzzleStage generatePuzzleStage;
@Mock
private RecordCustomMatchMetricsStage recordCustomMatchMetricsStage;
@Mock
private LoadFaceSamplesStage loadFaceSamplesStage;
@Mock
private CustomFaceSearchStage customFaceSearchStage;
@Mock
private LoadMatchedSamplesStage loadMatchedSamplesStage;
@Mock
private FilterByTimeRangeStage filterByTimeRangeStage;
@Mock
private FilterByDevicePhotoLimitStage filterByDevicePhotoLimitStage;
@Mock
private DeleteOldRelationsStage deleteOldRelationsStage;
@Mock
private ScenicConfigFacade scenicConfigFacade;
/**
* 测试Pipeline工厂能够成功创建Pipeline
*/
@@ -43,7 +107,7 @@ class FaceMatchingPipelineIntegrationTest {
// 验证Stage数量符合预期
assertEquals(13, autoMatchingNew.getStageCount());
assertEquals(13, autoMatchingOld.getStageCount());
assertEquals(12, autoMatchingOld.getStageCount());
assertEquals(15, customMatching.getStageCount());
assertEquals(3, recognitionOnly.getStageCount());
}

View File

@@ -1,5 +1,7 @@
package com.ycwl.basic.face.pipeline.stages;
import com.ycwl.basic.biz.FaceStatusManager;
import com.ycwl.basic.enums.FaceCutStatus;
import com.ycwl.basic.face.pipeline.core.FaceMatchingContext;
import com.ycwl.basic.pipeline.core.StageResult;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
@@ -27,6 +29,9 @@ class CreateTaskStageTest {
@Mock
private TaskService taskService;
@Mock
private FaceStatusManager faceStatusManager;
@InjectMocks
private CreateTaskStage stage;
@@ -60,7 +65,7 @@ class CreateTaskStageTest {
assertTrue(result.getMessage().contains("自动创建任务成功"));
verify(scenicConfigFacade, times(1)).isFaceSelectFirst(10L);
verify(taskService, times(1)).autoCreateTaskByFaceId(1L);
// verify(taskStatusBiz, never()).setFaceCutStatus(anyLong(), anyInt());
verify(faceStatusManager, never()).setFaceCutStatus(anyLong(), any(FaceCutStatus.class));
}
@Test
@@ -76,7 +81,7 @@ class CreateTaskStageTest {
assertTrue(result.isSkipped());
assertTrue(result.getMessage().contains("等待用户手动选择"));
verify(scenicConfigFacade, times(1)).isFaceSelectFirst(10L);
// verify(taskStatusBiz, times(1)).setFaceCutStatus(1L, 2);
verify(faceStatusManager, times(1)).setFaceCutStatus(1L, FaceCutStatus.WAITING_USER_SELECT);
verify(taskService, never()).autoCreateTaskByFaceId(anyLong());
}
@@ -94,7 +99,7 @@ class CreateTaskStageTest {
assertTrue(result.getMessage().contains("任务创建失败"));
verify(scenicConfigFacade, times(1)).isFaceSelectFirst(10L);
verify(taskService, never()).autoCreateTaskByFaceId(anyLong());
// verify(taskStatusBiz, never()).setFaceCutStatus(anyLong(), anyInt());
verify(faceStatusManager, never()).setFaceCutStatus(anyLong(), any(FaceCutStatus.class));
}
@Test
@@ -119,8 +124,8 @@ class CreateTaskStageTest {
// Given: 设置状态失败
when(scenicConfigFacade.isFaceSelectFirst(10L))
.thenReturn(true);
// doThrow(new RuntimeException("Status set error"))
// .when(taskStatusBiz).setFaceCutStatus(1L, 2);
doThrow(new RuntimeException("Status set error"))
.when(faceStatusManager).setFaceCutStatus(1L, FaceCutStatus.WAITING_USER_SELECT);
// When
StageResult<FaceMatchingContext> result = stage.execute(context);
@@ -128,7 +133,7 @@ class CreateTaskStageTest {
// Then
assertTrue(result.isDegraded());
assertTrue(result.getMessage().contains("任务创建失败"));
// verify(taskStatusBiz, times(1)).setFaceCutStatus(1L, 2);
verify(faceStatusManager, times(1)).setFaceCutStatus(1L, FaceCutStatus.WAITING_USER_SELECT);
}
@Test

View File

@@ -1,5 +1,6 @@
package com.ycwl.basic.face.pipeline.stages;
import com.ycwl.basic.biz.FaceStatusManager;
import com.ycwl.basic.face.pipeline.core.FaceMatchingContext;
import com.ycwl.basic.pipeline.core.StageResult;
import com.ycwl.basic.mapper.SourceMapper;
@@ -32,6 +33,9 @@ class DeleteOldRelationsStageTest {
@Mock
private MemberRelationRepository memberRelationRepository;
@Mock
private FaceStatusManager faceStatusManager;
@InjectMocks
private DeleteOldRelationsStage stage;
@@ -63,6 +67,7 @@ class DeleteOldRelationsStageTest {
verify(sourceMapper, times(1)).deleteNotBuyFaceRelation(100L, 1L);
verify(videoMapper, times(1)).deleteNotBuyFaceRelations(100L, 1L);
verify(memberRelationRepository, times(1)).clearSCacheByFace(1L);
verify(faceStatusManager, times(1)).invalidatePuzzleSourceVersion(1L);
}
@Test
@@ -80,6 +85,7 @@ class DeleteOldRelationsStageTest {
verify(sourceMapper, times(1)).deleteNotBuyFaceRelation(100L, 1L);
verify(videoMapper, never()).deleteNotBuyFaceRelations(anyLong(), anyLong());
verify(memberRelationRepository, never()).clearSCacheByFace(anyLong());
verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
}
@Test
@@ -96,6 +102,7 @@ class DeleteOldRelationsStageTest {
verify(sourceMapper, times(1)).deleteNotBuyFaceRelation(100L, 1L);
verify(videoMapper, times(1)).deleteNotBuyFaceRelations(100L, 1L);
verify(memberRelationRepository, never()).clearSCacheByFace(anyLong());
verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
}
@Test
@@ -110,6 +117,7 @@ class DeleteOldRelationsStageTest {
// Then
assertTrue(result.isDegraded());
verify(memberRelationRepository, times(1)).clearSCacheByFace(1L);
verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
}
@Test
@@ -124,6 +132,7 @@ class DeleteOldRelationsStageTest {
assertTrue(result.isSuccess());
verify(sourceMapper, times(1)).deleteNotBuyFaceRelation(999L, 1L);
verify(videoMapper, times(1)).deleteNotBuyFaceRelations(999L, 1L);
verify(faceStatusManager, times(1)).invalidatePuzzleSourceVersion(1L);
}
@Test
@@ -141,6 +150,7 @@ class DeleteOldRelationsStageTest {
verify(sourceMapper, times(1)).deleteNotBuyFaceRelation(100L, 888L);
verify(videoMapper, times(1)).deleteNotBuyFaceRelations(100L, 888L);
verify(memberRelationRepository, times(1)).clearSCacheByFace(888L);
verify(faceStatusManager, times(1)).invalidatePuzzleSourceVersion(888L);
}
@Test
@@ -155,6 +165,7 @@ class DeleteOldRelationsStageTest {
// Then
assertTrue(result.isDegraded());
assertTrue(result.getMessage().contains("删除旧关系数据失败"));
verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
}
@Test
@@ -171,5 +182,6 @@ class DeleteOldRelationsStageTest {
// source删除成功,但video删除失败
verify(sourceMapper, times(1)).deleteNotBuyFaceRelation(100L, 1L);
verify(videoMapper, times(1)).deleteNotBuyFaceRelations(100L, 1L);
verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
}
}

View File

@@ -1,5 +1,6 @@
package com.ycwl.basic.face.pipeline.stages;
import com.ycwl.basic.biz.FaceStatusManager;
import com.ycwl.basic.face.pipeline.core.FaceMatchingContext;
import com.ycwl.basic.pipeline.core.StageResult;
import com.ycwl.basic.mapper.SourceMapper;
@@ -33,6 +34,9 @@ class PersistRelationsStageTest {
@Mock
private MemberRelationRepository memberRelationRepository;
@Mock
private FaceStatusManager faceStatusManager;
@InjectMocks
private PersistRelationsStage stage;
@@ -67,6 +71,7 @@ class PersistRelationsStageTest {
verify(sourceMapper, times(1)).filterValidSourceRelations(afterExistingFilter);
verify(sourceMapper, times(1)).addRelations(afterValidFilter);
verify(memberRelationRepository, times(1)).clearSCacheByFace(1L);
verify(faceStatusManager, times(1)).invalidatePuzzleSourceVersion(1L);
}
@Test
@@ -82,6 +87,7 @@ class PersistRelationsStageTest {
assertTrue(result.getMessage().contains("memberSourceList为空"));
verify(sourceMapper, never()).filterExistingRelations(anyList());
verify(sourceMapper, never()).addRelations(anyList());
verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
}
@Test
@@ -96,6 +102,7 @@ class PersistRelationsStageTest {
assertTrue(result.isSkipped());
assertTrue(result.getMessage().contains("memberSourceList为空"));
verify(sourceMapper, never()).filterExistingRelations(anyList());
verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
}
@Test
@@ -116,6 +123,7 @@ class PersistRelationsStageTest {
verify(sourceMapper, times(1)).filterExistingRelations(memberSourceList);
verify(sourceMapper, never()).addRelations(anyList());
verify(memberRelationRepository, never()).clearSCacheByFace(anyLong());
verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
}
@Test
@@ -139,6 +147,7 @@ class PersistRelationsStageTest {
assertTrue(result.getMessage().contains("没有有效的关联关系可创建"));
verify(sourceMapper, times(1)).filterValidSourceRelations(afterExistingFilter);
verify(sourceMapper, never()).addRelations(anyList());
verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
}
@Test
@@ -162,6 +171,7 @@ class PersistRelationsStageTest {
assertTrue(result.isSuccess());
assertTrue(result.getMessage().contains("持久化了5条关联关系"));
verify(sourceMapper, times(1)).addRelations(afterValidFilter);
verify(faceStatusManager, times(1)).invalidatePuzzleSourceVersion(1L);
}
@Test
@@ -181,6 +191,7 @@ class PersistRelationsStageTest {
assertTrue(result.getMessage().contains("保存关联关系失败"));
assertNotNull(result.getException());
verify(sourceMapper, never()).addRelations(anyList());
verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
}
@Test
@@ -204,6 +215,7 @@ class PersistRelationsStageTest {
// Then
assertTrue(result.isFailed());
verify(memberRelationRepository, never()).clearSCacheByFace(anyLong()); // 失败时不清缓存
verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
}
@Test
@@ -228,6 +240,7 @@ class PersistRelationsStageTest {
// Then
assertTrue(result.isFailed()); // 缓存清理失败导致整体失败
verify(sourceMapper, times(1)).addRelations(afterValidFilter); // 但关系已保存
verify(faceStatusManager, never()).invalidatePuzzleSourceVersion(anyLong());
}
@Test
@@ -247,6 +260,7 @@ class PersistRelationsStageTest {
// Then
assertTrue(result.isSuccess());
assertTrue(result.getMessage().contains("持久化了1条关联关系"));
verify(faceStatusManager, times(1)).invalidatePuzzleSourceVersion(1L);
}
private List<MemberSourceEntity> createMemberSourceList(int count) {

View File

@@ -1,16 +1,21 @@
package com.ycwl.basic.face.pipeline.stages;
import com.ycwl.basic.biz.FaceStatusManager;
import com.ycwl.basic.enums.FaceCutStatus;
import com.ycwl.basic.face.pipeline.core.FaceMatchingContext;
import com.ycwl.basic.pipeline.core.StageResult;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.*;
/**
* SetTaskStatusStage 单元测试
@@ -21,6 +26,9 @@ class SetTaskStatusStageTest {
@InjectMocks
private SetTaskStatusStage stage;
@Mock
private FaceStatusManager faceStatusManager;
private FaceMatchingContext context;
@BeforeEach
@@ -41,7 +49,7 @@ class SetTaskStatusStageTest {
// Then
assertTrue(result.isSuccess());
assertTrue(result.getMessage().contains("任务状态已设置"));
// verify(taskStatusBiz, times(1)).setFaceCutStatus(1L, 0);
verify(faceStatusManager, times(1)).setFaceCutStatus(1L, FaceCutStatus.CUTTING);
}
@Test
@@ -55,7 +63,7 @@ class SetTaskStatusStageTest {
// Then
assertTrue(result.isSkipped());
assertTrue(result.getMessage().contains("非新用户"));
// verify(taskStatusBiz, never()).setFaceCutStatus(anyLong(), anyInt());
verify(faceStatusManager, never()).setFaceCutStatus(anyLong(), any(FaceCutStatus.class));
}
@Test
@@ -63,8 +71,8 @@ class SetTaskStatusStageTest {
// Given
context = FaceMatchingContext.forAutoMatching(1L, true);
// doThrow(new RuntimeException("Database error"))
// .when(taskStatusBiz).setFaceCutStatus(1L, 0);
doThrow(new RuntimeException("Database error"))
.when(faceStatusManager).setFaceCutStatus(1L, FaceCutStatus.CUTTING);
// When
StageResult<FaceMatchingContext> result = stage.execute(context);
@@ -72,7 +80,7 @@ class SetTaskStatusStageTest {
// Then
assertTrue(result.isDegraded()); // 降级处理,不影响主流程
assertTrue(result.getMessage().contains("任务状态设置失败"));
// verify(taskStatusBiz, times(1)).setFaceCutStatus(1L, 0);
verify(faceStatusManager, times(1)).setFaceCutStatus(1L, FaceCutStatus.CUTTING);
}
@Test
@@ -87,7 +95,7 @@ class SetTaskStatusStageTest {
// Then
assertTrue(result.isSuccess());
// verify(taskStatusBiz, times(1)).setFaceCutStatus(999L, 0);
verify(faceStatusManager, times(1)).setFaceCutStatus(999L, FaceCutStatus.CUTTING);
}
@Test
@@ -100,7 +108,7 @@ class SetTaskStatusStageTest {
// Then
assertTrue(result.isSkipped());
// verify(taskStatusBiz, never()).setFaceCutStatus(anyLong(), anyInt());
verify(faceStatusManager, never()).setFaceCutStatus(anyLong(), any(FaceCutStatus.class));
}
@Test
@@ -114,7 +122,7 @@ class SetTaskStatusStageTest {
// Then
assertTrue(result.isSkipped());
// verify(taskStatusBiz, never()).setFaceCutStatus(anyLong(), anyInt());
verify(faceStatusManager, never()).setFaceCutStatus(anyLong(), any(FaceCutStatus.class));
}
@Test
@@ -122,8 +130,8 @@ class SetTaskStatusStageTest {
// Given
context = FaceMatchingContext.forAutoMatching(1L, true);
// doThrow(new NullPointerException("Null task status"))
// .when(taskStatusBiz).setFaceCutStatus(1L, 0);
doThrow(new NullPointerException("Null task status"))
.when(faceStatusManager).setFaceCutStatus(1L, FaceCutStatus.CUTTING);
// When
StageResult<FaceMatchingContext> result = stage.execute(context);
@@ -131,6 +139,7 @@ class SetTaskStatusStageTest {
// Then
assertTrue(result.isDegraded());
assertTrue(result.getMessage().contains("任务状态设置失败"));
verify(faceStatusManager, times(1)).setFaceCutStatus(1L, FaceCutStatus.CUTTING);
}
@Test
@@ -143,6 +152,7 @@ class SetTaskStatusStageTest {
// Then
assertFalse(result.isSkipped()); // 应该执行
verify(faceStatusManager, times(1)).setFaceCutStatus(1L, FaceCutStatus.CUTTING);
}
@Test
@@ -155,5 +165,6 @@ class SetTaskStatusStageTest {
// Then
assertTrue(result.isSkipped()); // 应该跳过
verify(faceStatusManager, never()).setFaceCutStatus(anyLong(), any(FaceCutStatus.class));
}
}

View File

@@ -19,7 +19,7 @@ class PipelineBuilderTest {
Exception exception = assertThrows(IllegalStateException.class, builder::build);
assertEquals("管线至少需要一个Stage", exception.getMessage());
assertEquals("Pipeline 至少需要一个 Stage", exception.getMessage());
}
@Test

View File

@@ -146,8 +146,13 @@ class ImageEnhanceStageTest {
}
@Test
void testExecute_NoCurrentFile_ShouldFail() {
ImageEnhanceStage stage = new ImageEnhanceStage();
void testExecute_NoCurrentFile_ShouldSkip() {
BceEnhancerConfig validConfig = new BceEnhancerConfig();
validConfig.setAppId("valid-app-id");
validConfig.setApiKey("valid-api-key");
validConfig.setSecretKey("valid-secret-key");
ImageEnhanceStage stage = new ImageEnhanceStage(validConfig);
PhotoProcessContext context = PhotoProcessContext.builder()
.originalUrl("https://example.com/test.jpg")
@@ -157,7 +162,7 @@ class ImageEnhanceStageTest {
StageResult result = stage.execute(context);
assertTrue(result.isFailed());
assertTrue(result.isSkipped());
assertEquals("当前文件不存在", result.getMessage());
}

View File

@@ -1,16 +1,15 @@
package com.ycwl.basic.pricing.service.impl;
import com.ycwl.basic.order.service.IOrderService;
import com.ycwl.basic.pricing.dto.OnePriceInfo;
import com.ycwl.basic.pricing.dto.BundleDiscountInfo;
import com.ycwl.basic.pricing.dto.ProductItem;
import com.ycwl.basic.pricing.dto.UpgradeCheckRequest;
import com.ycwl.basic.pricing.dto.UpgradeCheckResult;
import com.ycwl.basic.pricing.entity.PriceBundleConfig;
import com.ycwl.basic.pricing.entity.PriceProductConfig;
import com.ycwl.basic.pricing.enums.ProductType;
import com.ycwl.basic.pricing.service.IBundleDiscountService;
import com.ycwl.basic.pricing.service.ICouponService;
import com.ycwl.basic.pricing.service.IDiscountDetectionService;
import com.ycwl.basic.pricing.service.IOnePricePurchaseService;
import com.ycwl.basic.pricing.service.IPriceBundleService;
import com.ycwl.basic.pricing.service.IProductConfigService;
import com.ycwl.basic.pricing.service.IVoucherService;
@@ -42,28 +41,26 @@ class PriceCalculationServiceImplUpgradeCheckTest {
@Mock
private IPriceBundleService bundleService;
@Mock
private IOnePricePurchaseService onePricePurchaseService;
private IBundleDiscountService bundleDiscountService;
@Mock
private IDiscountDetectionService discountDetectionService;
@Mock
private IVoucherService voucherService;
@Mock
private IProductTypeCapabilityService productTypeCapabilityService;
@Mock
private IOrderService orderService;
@InjectMocks
private PriceCalculationServiceImpl priceCalculationService;
@Test
void shouldSelectOnePriceWhenUpgradeTypeSpecified() {
void shouldSelectOnePriceWhenCheaper() {
mockProductConfig(new BigDecimal("100.00"));
when(onePricePurchaseService.getOnePriceInfo(eq(1L), any()))
.thenReturn(buildOnePriceInfo(new BigDecimal("80.00")));
when(bundleService.getCheapestBundleConfig(any()))
.thenReturn(buildBundleConfig(new BigDecimal("50.00")));
when(bundleService.getBundleConfig(any()))
.thenReturn(buildBundleConfig(new BigDecimal("80.00")));
when(bundleDiscountService.getBestBundleDiscount(any(), eq(1L)))
.thenReturn(buildBundleDiscountInfo(new BigDecimal("10.00")));
UpgradeCheckRequest request = buildRequest("ONE_PRICE");
UpgradeCheckRequest request = buildRequest();
UpgradeCheckResult result = priceCalculationService.checkUpgrade(request);
assertEquals("ONE_PRICE", result.getBestUpgradeType());
@@ -71,14 +68,14 @@ class PriceCalculationServiceImplUpgradeCheckTest {
}
@Test
void shouldSelectCheapestBundleWhenUpgradeTypeMissing() {
void shouldSelectBundleDiscountWhenCheaper() {
mockProductConfig(new BigDecimal("100.00"));
when(onePricePurchaseService.getOnePriceInfo(eq(1L), any()))
.thenReturn(buildOnePriceInfo(new BigDecimal("80.00")));
when(bundleService.getCheapestBundleConfig(any()))
.thenReturn(buildBundleConfig(new BigDecimal("70.00")));
when(bundleService.getBundleConfig(any()))
.thenReturn(buildBundleConfig(new BigDecimal("80.00")));
when(bundleDiscountService.getBestBundleDiscount(any(), eq(1L)))
.thenReturn(buildBundleDiscountInfo(new BigDecimal("30.00")));
UpgradeCheckRequest request = buildRequest(null);
UpgradeCheckRequest request = buildRequest();
UpgradeCheckResult result = priceCalculationService.checkUpgrade(request);
assertEquals("BUNDLE_DISCOUNT", result.getBestUpgradeType());
@@ -86,14 +83,14 @@ class PriceCalculationServiceImplUpgradeCheckTest {
}
@Test
void shouldReturnNullBestWhenOnePriceNotApplicable() {
void shouldReturnNullBestWhenNoUpgradeApplicable() {
mockProductConfig(new BigDecimal("100.00"));
when(onePricePurchaseService.getOnePriceInfo(eq(1L), any()))
.thenReturn(buildOnePriceInfo(new BigDecimal("120.00")));
when(bundleService.getCheapestBundleConfig(any()))
.thenReturn(buildBundleConfig(new BigDecimal("70.00")));
when(bundleService.getBundleConfig(any()))
.thenReturn(null);
when(bundleDiscountService.getBestBundleDiscount(any(), eq(1L)))
.thenReturn(null);
UpgradeCheckRequest request = buildRequest("ONE_PRICE");
UpgradeCheckRequest request = buildRequest();
UpgradeCheckResult result = priceCalculationService.checkUpgrade(request);
assertNull(result.getBestUpgradeType());
@@ -112,15 +109,13 @@ class PriceCalculationServiceImplUpgradeCheckTest {
.thenReturn(config);
}
private UpgradeCheckRequest buildRequest(String upgradeType) {
private UpgradeCheckRequest buildRequest() {
UpgradeCheckRequest request = new UpgradeCheckRequest();
request.setScenicId(1L);
request.setFaceId(2L);
request.setMemberId(3L);
request.setPaidAmount(BigDecimal.ZERO);
request.setPurchasedProducts(List.of());
request.setIntendingProducts(List.of(buildProductItem()));
request.setUpgradeType(upgradeType);
return request;
}
@@ -133,17 +128,6 @@ class PriceCalculationServiceImplUpgradeCheckTest {
return item;
}
private OnePriceInfo buildOnePriceInfo(BigDecimal onePrice) {
OnePriceInfo info = new OnePriceInfo();
info.setConfigId(10L);
info.setConfigName("一口价");
info.setScenicId(1L);
info.setOnePrice(onePrice);
info.setOriginalPrice(onePrice);
info.setDescription("一口价测试");
return info;
}
private PriceBundleConfig buildBundleConfig(BigDecimal bundlePrice) {
PriceBundleConfig config = new PriceBundleConfig();
config.setId(20L);
@@ -153,4 +137,17 @@ class PriceCalculationServiceImplUpgradeCheckTest {
config.setDescription("打包购买测试");
return config;
}
private BundleDiscountInfo buildBundleDiscountInfo(BigDecimal discountAmount) {
BundleDiscountInfo info = new BundleDiscountInfo();
info.setBundleConfigId(30L);
info.setBundleName("打包购买");
info.setBundleDescription("打包购买测试");
info.setDiscountType("FIXED_DISCOUNT");
info.setDiscountValue(discountAmount);
info.setActualDiscountAmount(discountAmount);
info.setMinQuantity(1);
info.setMinAmount(BigDecimal.ZERO);
return info;
}
}

View File

@@ -30,7 +30,7 @@ public class ProductTypeCapabilityServiceTest {
assertNotNull(capability);
assertEquals("VLOG_VIDEO", capability.getProductType());
assertEquals("Vlog视频", capability.getDisplayName());
assertEquals("VIDEO", capability.getCategory());
assertEquals("VLOG", capability.getCategory());
assertEquals(PricingMode.FIXED, capability.getPricingModeEnum());
assertEquals(false, capability.getAllowDuplicatePurchase());
assertEquals(DuplicateCheckStrategy.UNIQUE_RESOURCE, capability.getDuplicateCheckStrategyEnum());