diff --git a/continew-admin-business/src/main/java/top/continew/admin/business/model/req/DigitalHumanReq.java b/continew-admin-business/src/main/java/top/continew/admin/business/model/req/DigitalHumanReq.java index 8f828dc..c8f3ccb 100644 --- a/continew-admin-business/src/main/java/top/continew/admin/business/model/req/DigitalHumanReq.java +++ b/continew-admin-business/src/main/java/top/continew/admin/business/model/req/DigitalHumanReq.java @@ -2,8 +2,13 @@ package top.continew.admin.business.model.req; import lombok.Data; import lombok.EqualsAndHashCode; +import top.continew.admin.business.model.entity.Effect; +import top.continew.admin.business.model.entity.SubtitleItem; +import top.continew.admin.business.model.entity.SubtitleStyle; import top.continew.starter.extension.crud.model.req.BaseReq; +import java.util.List; + /** * 数字人请求参数对象 * @@ -42,15 +47,15 @@ public class DigitalHumanReq extends BaseReq { /** * 字幕项列表(冗余存储,用于快速回显) */ - private String subtitle; + private List subtitles; /** * 字幕样式配置(冗余或快照) */ - private String subtitleStyle; + private SubtitleStyle subtitleStyle; /** * 特效列表(冗余存储) */ - private String effects; + private List effects; } \ No newline at end of file diff --git a/continew-admin-business/src/main/java/top/continew/admin/business/service/impl/DigitalHumanServiceImpl.java b/continew-admin-business/src/main/java/top/continew/admin/business/service/impl/DigitalHumanServiceImpl.java index 8c1c121..a4a498f 100644 --- a/continew-admin-business/src/main/java/top/continew/admin/business/service/impl/DigitalHumanServiceImpl.java +++ b/continew-admin-business/src/main/java/top/continew/admin/business/service/impl/DigitalHumanServiceImpl.java @@ -20,6 +20,7 @@ import top.continew.admin.business.service.DigitalHumanService; import top.continew.starter.extension.crud.model.resp.PageResp; import top.continew.starter.extension.crud.service.impl.BaseServiceImpl; +import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; @@ -96,25 +97,136 @@ public class DigitalHumanServiceImpl extends BaseServiceImpl ids) { + for (Long id : ids) { + // 删除关联的特效 + LambdaQueryWrapper effectWrapper = new LambdaQueryWrapper<>(); + effectWrapper.eq(Effect::getDigitalHumanId, id); + effectMapper.delete(effectWrapper); + + // 删除关联的字幕项 + LambdaQueryWrapper subtitleItemWrapper = new LambdaQueryWrapper<>(); + subtitleItemWrapper.eq(SubtitleItem::getDigitalHumanId, id); + subtitleItemMapper.delete(subtitleItemWrapper); + + // 删除关联的字幕样式 + LambdaQueryWrapper subtitleStyleWrapper = new LambdaQueryWrapper<>(); + subtitleStyleWrapper.eq(SubtitleStyle::getDigitalHumanId, id); + subtitleStyleMapper.delete(subtitleStyleWrapper); + } + + // 删除数字人 digitalHumanMapper.deleteBatchIds(ids); } @Override public void update(DigitalHumanReq req, Long id) { DigitalHuman digitalHuman = new DigitalHuman(); - BeanUtils.copyProperties(req, digitalHuman); + // 只复制基本字段,不包括关联的列表字段 digitalHuman.setId(id); + digitalHuman.setUserId(req.getUserId()); + digitalHuman.setCopywriting(req.getCopywriting()); + digitalHuman.setGeneratedVoiceUrl(req.getGeneratedVoiceUrl()); + digitalHuman.setGeneratedFrameImageUrl(req.getGeneratedFrameImageUrl()); + digitalHuman.setGeneratedVideoUrl(req.getGeneratedVideoUrl()); digitalHuman.setUpdateTime(java.time.LocalDateTime.now()); digitalHumanMapper.updateById(digitalHuman); + + // 更新或保存字幕样式 + if (req.getSubtitleStyle() != null) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SubtitleStyle::getDigitalHumanId, id); + List existingStyles = subtitleStyleMapper.selectList(wrapper); + + SubtitleStyle subtitleStyle = req.getSubtitleStyle(); + subtitleStyle.setDigitalHumanId(id); + subtitleStyle.setUpdateTime(java.time.LocalDateTime.now()); + + if (existingStyles != null && !existingStyles.isEmpty()) { + // 如果已存在样式记录,更新第一个记录 + subtitleStyle.setId(existingStyles.get(0).getId()); + subtitleStyleMapper.updateById(subtitleStyle); + } else { + // 如果不存在样式记录,创建新记录 + subtitleStyle.setCreateTime(java.time.LocalDateTime.now()); + subtitleStyleMapper.insert(subtitleStyle); + } + } + + // 删除旧的字幕项,然后保存新的字幕项 + LambdaQueryWrapper subtitleItemWrapper = new LambdaQueryWrapper<>(); + subtitleItemWrapper.eq(SubtitleItem::getDigitalHumanId, id); + subtitleItemMapper.delete(subtitleItemWrapper); + + if (req.getSubtitles() != null && !req.getSubtitles().isEmpty()) { + LocalDateTime now = LocalDateTime.now(); + for (SubtitleItem subtitleItem : req.getSubtitles()) { + subtitleItem.setDigitalHumanId(id); + subtitleItem.setCreateTime(now); + subtitleItem.setUpdateTime(now); + subtitleItemMapper.insert(subtitleItem); + } + } + + // 删除旧的特效,然后保存新的特效 + LambdaQueryWrapper effectWrapper = new LambdaQueryWrapper<>(); + effectWrapper.eq(Effect::getDigitalHumanId, id); + effectMapper.delete(effectWrapper); + + if (req.getEffects() != null && !req.getEffects().isEmpty()) { + LocalDateTime now = LocalDateTime.now(); + for (Effect effect : req.getEffects()) { + effect.setDigitalHumanId(id); + effect.setCreateTime(now); + effect.setUpdateTime(now); + effectMapper.insert(effect); + } + } } private DigitalHumanResp convertToResp(DigitalHuman digitalHuman) { diff --git a/continew-admin-business/src/main/java/top/continew/admin/business/service/impl/SubtitleItemServiceImpl.java b/continew-admin-business/src/main/java/top/continew/admin/business/service/impl/SubtitleItemServiceImpl.java index f62b369..b35d11c 100644 --- a/continew-admin-business/src/main/java/top/continew/admin/business/service/impl/SubtitleItemServiceImpl.java +++ b/continew-admin-business/src/main/java/top/continew/admin/business/service/impl/SubtitleItemServiceImpl.java @@ -89,10 +89,10 @@ public class SubtitleItemServiceImpl extends BaseServiceImpl ids = new ArrayList<>(); LocalDateTime now = LocalDateTime.now(); - + // 遍历逐个插入,获取每个id for (SubtitleItemReq req : reqList) { SubtitleItem subtitleItem = new SubtitleItem(); @@ -103,7 +103,7 @@ public class SubtitleItemServiceImpl extends BaseServiceImplspring-boot-starter-test test + + + + com.h2database + h2 + test + cn.dev33 sa-token-core diff --git a/continew-admin-webapi/src/main/resources/config/application-test.yml b/continew-admin-webapi/src/main/resources/config/application-test.yml index e4cc04d..55cd20b 100644 --- a/continew-admin-webapi/src/main/resources/config/application-test.yml +++ b/continew-admin-webapi/src/main/resources/config/application-test.yml @@ -15,7 +15,7 @@ spring.datasource: ## 动态数据源配置(可配多主多从:m1、s1...;纯粹多库:mysql、oracle...;混合配置:m1、s1、oracle...) dynamic: # 是否启用 P6Spy(SQL 性能分析组件,该插件有性能损耗,不建议生产环境使用) - p6spy: true + p6spy: false # 设置默认的数据源或者数据源组(默认:master) primary: digital_human # 严格匹配数据源(true:未匹配到指定数据源时抛异常;false:使用默认数据源;默认 false) @@ -23,31 +23,38 @@ spring.datasource: datasource: # 主库配置(可配多个,构成多主) digital_human: - url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:digital_human}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&autoReconnect=true&maxReconnects=10&failOverReadOnly=false&allowPublicKeyRetrieval=true - #url: jdbc:mysql://106.54.11.219:3306/digital_human?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&autoReconnect=true&maxReconnects=10&failOverReadOnly=false - username: ${DB_USER:root} - # password: ${DB_PWD:147369Wan} - password: ${DB_PWD:123456} - # password: ${DB_PWD:C9MUjc5ChtqHeCtQ} - driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:h2:mem:digital_human;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=MYSQL;DATABASE_TO_UPPER=FALSE + username: sa + password: + driver-class-name: org.h2.Driver type: ${spring.datasource.type} - hikari: - # 最大连接数量(默认 10,根据实际环境调整) - # 注意:当连接达到上限,并且没有空闲连接可用时,获取连接将在超时前阻塞最多 connectionTimeout 毫秒 - max-pool-size: 20 - # 获取连接超时时间(默认 30000 毫秒,30 秒) - connection-timeout: 30000 - # 空闲连接最大存活时间(默认 600000 毫秒,10 分钟) - idle-timeout: 600000 - # 保持连接活动的频率,以防止它被数据库或网络基础设施超时。该值必须小于 maxLifetime(默认 0,禁用) - keepaliveTime: 30000 - # 连接最大生存时间(默认 1800000 毫秒,30 分钟) - max-lifetime: 1800000 +spring.jpa: + hibernate: + ddl-auto: create-drop + show-sql: true + database-platform: org.hibernate.dialect.H2Dialect + +spring.h2.console: + enabled: true + path: /h2-console + +spring.datasource.dynamic.hikari: + # 最大连接数量(默认 10,根据实际环境调整) + # 注意:当连接达到上限,并且没有空闲连接可用时,获取连接将在超时前阻塞最多 connectionTimeout 毫秒 + max-pool-size: 20 + # 获取连接超时时间(默认 30000 毫秒,30 秒) + connection-timeout: 30000 + # 空闲连接最大存活时间(默认 600000 毫秒,10 分钟) + idle-timeout: 600000 + # 保持连接活动的频率,以防止它被数据库或网络基础设施超时。该值必须小于 maxLifetime(默认 0,禁用) + keepaliveTime: 30000 + # 连接最大生存时间(默认 1800000 毫秒,30 分钟) + max-lifetime: 1800000 ## Liquibase 配置 spring.liquibase: # 是否启用 - enabled: false + enabled: true # 配置文件路径 change-log: classpath:/db/changelog/db.changelog-master.yaml @@ -62,7 +69,7 @@ spring.data: port: 6379 # port: 16380 # 密码(未设置密码时请注释掉) - password: 123456 + # password: 123456 # 数据库索引 database: ${REDIS_DB:11} # 连接超时时间 @@ -72,7 +79,7 @@ spring.data: enabled: false ## Redisson 配置 redisson: - enabled: true + enabled: false mode: SINGLE ## JetCache 配置 jetcache: diff --git a/continew-admin-webapi/src/test/java/top/continew/admin/business/service/impl/DigitalHumanServiceImplTest.java b/continew-admin-webapi/src/test/java/top/continew/admin/business/service/impl/DigitalHumanServiceImplTest.java new file mode 100644 index 0000000..b318205 --- /dev/null +++ b/continew-admin-webapi/src/test/java/top/continew/admin/business/service/impl/DigitalHumanServiceImplTest.java @@ -0,0 +1,235 @@ +package top.continew.admin.business.service.impl; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.Rollback; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; +import top.continew.admin.business.mapper.DigitalHumanMapper; +import top.continew.admin.business.mapper.EffectMapper; +import top.continew.admin.business.mapper.SubtitleItemMapper; +import top.continew.admin.business.mapper.SubtitleStyleMapper; +import top.continew.admin.business.model.entity.DigitalHuman; +import top.continew.admin.business.model.entity.Effect; +import top.continew.admin.business.model.entity.SubtitleItem; +import top.continew.admin.business.model.entity.SubtitleStyle; +import top.continew.admin.business.model.req.DigitalHumanReq; +import top.continew.admin.business.service.DigitalHumanService; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * 数字人服务实现类测试 + * + * @author 王志维 + * @since 2025/12/29 + */ +@SpringBootTest +@ActiveProfiles("test") +@Transactional +@Rollback(true) +class DigitalHumanServiceImplTest { + + @Autowired + private DigitalHumanService digitalHumanService; + + @Autowired + private DigitalHumanMapper digitalHumanMapper; + + @Autowired + private SubtitleStyleMapper subtitleStyleMapper; + + @Autowired + private SubtitleItemMapper subtitleItemMapper; + + @Autowired + private EffectMapper effectMapper; + + private DigitalHumanReq createDigitalHumanReq() { + DigitalHumanReq req = new DigitalHumanReq(); + req.setUserId("1"); + req.setCopywriting("测试文案"); + req.setGeneratedVoiceUrl("http://test.com/voice.mp3"); + req.setGeneratedFrameImageUrl("http://test.com/frame.jpg"); + req.setGeneratedVideoUrl("http://test.com/video.mp4"); + + // 添加字幕样式 + SubtitleStyle subtitleStyle = new SubtitleStyle(); + subtitleStyle.setFontSize(16); + subtitleStyle.setColor("#FFFFFF"); + subtitleStyle.setStrokeColor("#000000"); + subtitleStyle.setStrokeWidth(2); + req.setSubtitleStyle(subtitleStyle); + + // 添加字幕项 + SubtitleItem subtitleItem1 = new SubtitleItem(); + subtitleItem1.setStartTime(0.0); + subtitleItem1.setEndTime(1.0); + subtitleItem1.setText("测试字幕1"); + + SubtitleItem subtitleItem2 = new SubtitleItem(); + subtitleItem2.setStartTime(1.0); + subtitleItem2.setEndTime(2.0); + subtitleItem2.setText("测试字幕2"); + + req.setSubtitles(List.of(subtitleItem1, subtitleItem2)); + + // 添加特效 + Effect effect1 = new Effect(); + effect1.setType("text"); + effect1.setName("测试特效1"); + effect1.setSourceUrl("http://test.com/effect1.mp4"); + effect1.setLength(5.0); + + Effect effect2 = new Effect(); + effect2.setType("image"); + effect2.setName("测试特效2"); + effect2.setSourceUrl("http://test.com/effect2.jpg"); + effect2.setLength(3.0); + + req.setEffects(List.of(effect1, effect2)); + + return req; + } + + @Test + void testAdd() { + DigitalHumanReq req = createDigitalHumanReq(); + Long id = digitalHumanService.add(req); + + assertNotNull(id); + + // 验证数字人基本信息 + DigitalHuman digitalHuman = digitalHumanMapper.selectById(id); + assertNotNull(digitalHuman); + assertEquals(req.getUserId(), digitalHuman.getUserId()); + assertEquals(req.getCopywriting(), digitalHuman.getCopywriting()); + + // 验证字幕样式 + List subtitleStyles = subtitleStyleMapper.selectList(null); + assertFalse(subtitleStyles.isEmpty()); + SubtitleStyle savedStyle = subtitleStyles.stream() + .filter(style -> style.getDigitalHumanId().equals(id)) + .findFirst() + .orElse(null); + assertNotNull(savedStyle); + assertEquals(req.getSubtitleStyle().getFontSize(), savedStyle.getFontSize()); + assertEquals(req.getSubtitleStyle().getColor(), savedStyle.getColor()); + + // 验证字幕项 + List subtitleItems = subtitleItemMapper.selectList(null); + assertFalse(subtitleItems.isEmpty()); + long subtitleCount = subtitleItems.stream().filter(item -> item.getDigitalHumanId().equals(id)).count(); + assertEquals(2, subtitleCount); + + // 验证特效 + List effects = effectMapper.selectList(null); + assertFalse(effects.isEmpty()); + long effectCount = effects.stream().filter(effect -> effect.getDigitalHumanId().equals(id)).count(); + assertEquals(2, effectCount); + } + + @Test + void testUpdate() { + // 先添加一个数字人 + DigitalHumanReq addReq = createDigitalHumanReq(); + Long id = digitalHumanService.add(addReq); + assertNotNull(id); + + // 准备更新数据 + DigitalHumanReq updateReq = new DigitalHumanReq(); + updateReq.setUserId("1"); + updateReq.setCopywriting("更新后的文案"); + updateReq.setGeneratedVoiceUrl("http://test.com/voice-updated.mp3"); + updateReq.setGeneratedFrameImageUrl("http://test.com/frame-updated.jpg"); + updateReq.setGeneratedVideoUrl("http://test.com/video-updated.mp4"); + + // 更新字幕样式 + SubtitleStyle updatedStyle = new SubtitleStyle(); + updatedStyle.setFontSize(20); + updatedStyle.setColor("#FF0000"); + updatedStyle.setStrokeColor("#0000FF"); + updatedStyle.setStrokeWidth(3); + updateReq.setSubtitleStyle(updatedStyle); + + // 更新字幕项(只保留一个) + SubtitleItem updatedSubtitle = new SubtitleItem(); + updatedSubtitle.setStartTime(0.0); + updatedSubtitle.setEndTime(3.0); + updatedSubtitle.setText("更新后的字幕"); + updateReq.setSubtitles(List.of(updatedSubtitle)); + + // 更新特效(只保留一个) + Effect updatedEffect = new Effect(); + updatedEffect.setType("music"); + updatedEffect.setName("更新后的特效"); + updatedEffect.setSourceUrl("http://test.com/effect-updated.mp3"); + updatedEffect.setLength(4.0); + updateReq.setEffects(List.of(updatedEffect)); + + // 执行更新 + digitalHumanService.update(updateReq, id); + + // 验证数字人基本信息更新 + DigitalHuman updatedDigitalHuman = digitalHumanMapper.selectById(id); + assertNotNull(updatedDigitalHuman); + assertEquals(updateReq.getCopywriting(), updatedDigitalHuman.getCopywriting()); + assertEquals(updateReq.getGeneratedVoiceUrl(), updatedDigitalHuman.getGeneratedVoiceUrl()); + + // 验证字幕样式更新 + List subtitleStyles = subtitleStyleMapper.selectList(null); + SubtitleStyle savedStyle = subtitleStyles.stream() + .filter(style -> style.getDigitalHumanId().equals(id)) + .findFirst() + .orElse(null); + assertNotNull(savedStyle); + assertEquals(updatedStyle.getFontSize(), savedStyle.getFontSize()); + assertEquals(updatedStyle.getColor(), savedStyle.getColor()); + assertEquals(updatedStyle.getStrokeColor(), savedStyle.getStrokeColor()); + + // 验证字幕项更新(数量应为1) + List subtitleItems = subtitleItemMapper.selectList(null); + long subtitleCount = subtitleItems.stream().filter(item -> item.getDigitalHumanId().equals(id)).count(); + assertEquals(1, subtitleCount); + + // 验证特效更新(数量应为1) + List effects = effectMapper.selectList(null); + long effectCount = effects.stream().filter(effect -> effect.getDigitalHumanId().equals(id)).count(); + assertEquals(1, effectCount); + } + + @Test + void testDelete() { + // 先添加一个数字人 + DigitalHumanReq req = createDigitalHumanReq(); + Long id = digitalHumanService.add(req); + assertNotNull(id); + + // 验证添加成功 + assertNotNull(digitalHumanMapper.selectById(id)); + + // 执行删除 + digitalHumanService.delete(List.of(id)); + + // 验证数字人已删除 + assertNull(digitalHumanMapper.selectById(id)); + + // 验证关联的字幕样式已删除 + List subtitleStyles = subtitleStyleMapper.selectList(null); + long styleCount = subtitleStyles.stream().filter(style -> style.getDigitalHumanId().equals(id)).count(); + assertEquals(0, styleCount); + + // 验证关联的字幕项已删除 + List subtitleItems = subtitleItemMapper.selectList(null); + long subtitleCount = subtitleItems.stream().filter(item -> item.getDigitalHumanId().equals(id)).count(); + assertEquals(0, subtitleCount); + + // 验证关联的特效已删除 + List effects = effectMapper.selectList(null); + long effectCount = effects.stream().filter(effect -> effect.getDigitalHumanId().equals(id)).count(); + assertEquals(0, effectCount); + } +} diff --git a/continew-admin-webapi/src/test/java/top/continew/admin/business/service/impl/DigitalHumanServiceImplUnitTest.java b/continew-admin-webapi/src/test/java/top/continew/admin/business/service/impl/DigitalHumanServiceImplUnitTest.java new file mode 100644 index 0000000..6c26cd7 --- /dev/null +++ b/continew-admin-webapi/src/test/java/top/continew/admin/business/service/impl/DigitalHumanServiceImplUnitTest.java @@ -0,0 +1,189 @@ +package top.continew.admin.business.service.impl; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import top.continew.admin.business.mapper.DigitalHumanMapper; +import top.continew.admin.business.mapper.EffectMapper; +import top.continew.admin.business.mapper.SubtitleItemMapper; +import top.continew.admin.business.mapper.SubtitleStyleMapper; +import top.continew.admin.business.model.entity.DigitalHuman; +import top.continew.admin.business.model.entity.Effect; +import top.continew.admin.business.model.entity.SubtitleItem; +import top.continew.admin.business.model.entity.SubtitleStyle; +import top.continew.admin.business.model.req.DigitalHumanReq; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +/** + * 数字人服务实现类单元测试 + * + * @author 王志维 + * @since 2025/12/29 + */ +class DigitalHumanServiceImplUnitTest { + + @Mock + private DigitalHumanMapper digitalHumanMapper; + + @Mock + private SubtitleStyleMapper subtitleStyleMapper; + + @Mock + private SubtitleItemMapper subtitleItemMapper; + + @Mock + private EffectMapper effectMapper; + + @InjectMocks + private DigitalHumanServiceImpl digitalHumanService; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + private DigitalHumanReq createDigitalHumanReq() { + DigitalHumanReq req = new DigitalHumanReq(); + req.setUserId("1"); + req.setCopywriting("测试文案"); + req.setGeneratedVoiceUrl("http://test.com/voice.mp3"); + req.setGeneratedFrameImageUrl("http://test.com/frame.jpg"); + req.setGeneratedVideoUrl("http://test.com/video.mp4"); + + // 添加字幕样式 + SubtitleStyle subtitleStyle = new SubtitleStyle(); + subtitleStyle.setFontSize(16); + subtitleStyle.setColor("#FFFFFF"); + subtitleStyle.setStrokeColor("#000000"); + subtitleStyle.setStrokeWidth(2); + req.setSubtitleStyle(subtitleStyle); + + // 添加字幕项 + SubtitleItem subtitleItem1 = new SubtitleItem(); + subtitleItem1.setStartTime(0.0); + subtitleItem1.setEndTime(1.0); + subtitleItem1.setText("测试字幕1"); + + SubtitleItem subtitleItem2 = new SubtitleItem(); + subtitleItem2.setStartTime(1.0); + subtitleItem2.setEndTime(2.0); + subtitleItem2.setText("测试字幕2"); + + req.setSubtitles(List.of(subtitleItem1, subtitleItem2)); + + // 添加特效 + Effect effect1 = new Effect(); + effect1.setType("text"); + effect1.setName("测试特效1"); + effect1.setSourceUrl("http://test.com/effect1.mp4"); + effect1.setLength(5.0); + + Effect effect2 = new Effect(); + effect2.setType("image"); + effect2.setName("测试特效2"); + effect2.setSourceUrl("http://test.com/effect2.jpg"); + effect2.setLength(3.0); + + req.setEffects(List.of(effect1, effect2)); + + return req; + } + + @Test + void testAdd() { + // 准备测试数据 + DigitalHumanReq req = createDigitalHumanReq(); + + // 模拟mapper行为,设置id + when(digitalHumanMapper.insert(any(DigitalHuman.class))).thenAnswer(invocation -> { + DigitalHuman digitalHuman = invocation.getArgument(0); + digitalHuman.setId(1L); // 手动设置id + return 1; + }); + + // 执行测试 + Long id = digitalHumanService.add(req); + + // 验证结果 + assertNotNull(id); + + // 验证调用次数 + verify(digitalHumanMapper, times(1)).insert(any(DigitalHuman.class)); + verify(subtitleStyleMapper, times(1)).insert(any(SubtitleStyle.class)); + verify(subtitleItemMapper, times(2)).insert(any(SubtitleItem.class)); + verify(effectMapper, times(2)).insert(any(Effect.class)); + } + + @Test + void testUpdate() { + // 准备测试数据 + DigitalHumanReq req = createDigitalHumanReq(); + Long id = 1L; + + // 模拟现有字幕样式 + SubtitleStyle existingStyle = new SubtitleStyle(); + existingStyle.setId(100L); + existingStyle.setDigitalHumanId(id); + List existingStyles = new ArrayList<>(); + existingStyles.add(existingStyle); + when(subtitleStyleMapper.selectList(any())).thenReturn(existingStyles); + + // 执行测试 + digitalHumanService.update(req, id); + + // 验证调用次数 + verify(digitalHumanMapper, times(1)).updateById(any(DigitalHuman.class)); + verify(subtitleStyleMapper, times(1)).selectList(any()); + verify(subtitleStyleMapper, times(1)).updateById(any(SubtitleStyle.class)); + verify(subtitleItemMapper, times(1)).delete(any()); + verify(subtitleItemMapper, times(2)).insert(any(SubtitleItem.class)); + verify(effectMapper, times(1)).delete(any()); + verify(effectMapper, times(2)).insert(any(Effect.class)); + } + + @Test + void testUpdateWithNewSubtitleStyle() { + // 准备测试数据 + DigitalHumanReq req = createDigitalHumanReq(); + Long id = 1L; + + // 模拟没有现有字幕样式 + when(subtitleStyleMapper.selectList(any())).thenReturn(new ArrayList<>()); + + // 执行测试 + digitalHumanService.update(req, id); + + // 验证调用次数 + verify(digitalHumanMapper, times(1)).updateById(any(DigitalHuman.class)); + verify(subtitleStyleMapper, times(1)).selectList(any()); + verify(subtitleStyleMapper, times(1)).insert(any(SubtitleStyle.class)); // 应该调用insert而不是update + verify(subtitleItemMapper, times(1)).delete(any()); + verify(subtitleItemMapper, times(2)).insert(any(SubtitleItem.class)); + verify(effectMapper, times(1)).delete(any()); + verify(effectMapper, times(2)).insert(any(Effect.class)); + } + + @Test + void testDelete() { + // 准备测试数据 + Long id = 1L; + List ids = List.of(id); + + // 执行测试 + digitalHumanService.delete(ids); + + // 验证调用次数 + verify(effectMapper, times(1)).delete(any()); + verify(subtitleItemMapper, times(1)).delete(any()); + verify(subtitleStyleMapper, times(1)).delete(any()); + verify(digitalHumanMapper, times(1)).deleteBatchIds(ids); + } +} diff --git a/pom.xml b/pom.xml index 8dca58b..088b9ea 100644 --- a/pom.xml +++ b/pom.xml @@ -113,8 +113,8 @@ org.apache.maven.plugins maven-surefire-plugin - - true + + ${skipTests}