修复subtitleStyle字段更新问题,添加测试用例
This commit is contained in:
parent
4455c2c3ed
commit
de6a766ff9
|
|
@ -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<SubtitleItem> subtitles;
|
||||
|
||||
/**
|
||||
* 字幕样式配置(冗余或快照)
|
||||
*/
|
||||
private String subtitleStyle;
|
||||
private SubtitleStyle subtitleStyle;
|
||||
|
||||
/**
|
||||
* 特效列表(冗余存储)
|
||||
*/
|
||||
private String effects;
|
||||
private List<Effect> effects;
|
||||
}
|
||||
|
|
@ -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<DigitalHumanMapper,
|
|||
@Override
|
||||
public Long add(DigitalHumanReq req) {
|
||||
DigitalHuman digitalHuman = new DigitalHuman();
|
||||
BeanUtils.copyProperties(req, digitalHuman);
|
||||
// 只复制基本字段,不包括关联的列表字段
|
||||
digitalHuman.setUserId(req.getUserId());
|
||||
digitalHuman.setCopywriting(req.getCopywriting());
|
||||
digitalHuman.setGeneratedVoiceUrl(req.getGeneratedVoiceUrl());
|
||||
digitalHuman.setGeneratedFrameImageUrl(req.getGeneratedFrameImageUrl());
|
||||
digitalHuman.setGeneratedVideoUrl(req.getGeneratedVideoUrl());
|
||||
digitalHuman.setCreateTime(java.time.LocalDateTime.now());
|
||||
digitalHuman.setUpdateTime(java.time.LocalDateTime.now());
|
||||
digitalHumanMapper.insert(digitalHuman);
|
||||
|
||||
// 保存字幕样式
|
||||
if (req.getSubtitleStyle() != null) {
|
||||
SubtitleStyle subtitleStyle = req.getSubtitleStyle();
|
||||
subtitleStyle.setDigitalHumanId(digitalHuman.getId());
|
||||
subtitleStyle.setCreateTime(java.time.LocalDateTime.now());
|
||||
subtitleStyle.setUpdateTime(java.time.LocalDateTime.now());
|
||||
subtitleStyleMapper.insert(subtitleStyle);
|
||||
}
|
||||
|
||||
// 保存字幕项列表
|
||||
if (req.getSubtitles() != null && !req.getSubtitles().isEmpty()) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
for (SubtitleItem subtitleItem : req.getSubtitles()) {
|
||||
subtitleItem.setDigitalHumanId(digitalHuman.getId());
|
||||
subtitleItem.setCreateTime(now);
|
||||
subtitleItem.setUpdateTime(now);
|
||||
subtitleItemMapper.insert(subtitleItem);
|
||||
}
|
||||
}
|
||||
|
||||
// 保存特效列表
|
||||
if (req.getEffects() != null && !req.getEffects().isEmpty()) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
for (Effect effect : req.getEffects()) {
|
||||
effect.setDigitalHumanId(digitalHuman.getId());
|
||||
effect.setCreateTime(now);
|
||||
effect.setUpdateTime(now);
|
||||
effectMapper.insert(effect);
|
||||
}
|
||||
}
|
||||
|
||||
return digitalHuman.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(List<Long> ids) {
|
||||
for (Long id : ids) {
|
||||
// 删除关联的特效
|
||||
LambdaQueryWrapper<Effect> effectWrapper = new LambdaQueryWrapper<>();
|
||||
effectWrapper.eq(Effect::getDigitalHumanId, id);
|
||||
effectMapper.delete(effectWrapper);
|
||||
|
||||
// 删除关联的字幕项
|
||||
LambdaQueryWrapper<SubtitleItem> subtitleItemWrapper = new LambdaQueryWrapper<>();
|
||||
subtitleItemWrapper.eq(SubtitleItem::getDigitalHumanId, id);
|
||||
subtitleItemMapper.delete(subtitleItemWrapper);
|
||||
|
||||
// 删除关联的字幕样式
|
||||
LambdaQueryWrapper<SubtitleStyle> 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<SubtitleStyle> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(SubtitleStyle::getDigitalHumanId, id);
|
||||
List<SubtitleStyle> 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<SubtitleItem> 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<Effect> 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) {
|
||||
|
|
|
|||
|
|
@ -89,10 +89,10 @@ public class SubtitleItemServiceImpl extends BaseServiceImpl<SubtitleItemMapper,
|
|||
if (reqList == null || reqList.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
|
||||
List<Long> ids = new ArrayList<>();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
|
||||
// 遍历逐个插入,获取每个id
|
||||
for (SubtitleItemReq req : reqList) {
|
||||
SubtitleItem subtitleItem = new SubtitleItem();
|
||||
|
|
@ -103,7 +103,7 @@ public class SubtitleItemServiceImpl extends BaseServiceImpl<SubtitleItemMapper,
|
|||
save(subtitleItem);
|
||||
ids.add(subtitleItem.getId());
|
||||
}
|
||||
|
||||
|
||||
return ids;
|
||||
}
|
||||
}
|
||||
|
|
@ -73,6 +73,13 @@
|
|||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- H2 内存数据库(用于测试) -->
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-core</artifactId>
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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<SubtitleStyle> 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<SubtitleItem> subtitleItems = subtitleItemMapper.selectList(null);
|
||||
assertFalse(subtitleItems.isEmpty());
|
||||
long subtitleCount = subtitleItems.stream().filter(item -> item.getDigitalHumanId().equals(id)).count();
|
||||
assertEquals(2, subtitleCount);
|
||||
|
||||
// 验证特效
|
||||
List<Effect> 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<SubtitleStyle> 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<SubtitleItem> subtitleItems = subtitleItemMapper.selectList(null);
|
||||
long subtitleCount = subtitleItems.stream().filter(item -> item.getDigitalHumanId().equals(id)).count();
|
||||
assertEquals(1, subtitleCount);
|
||||
|
||||
// 验证特效更新(数量应为1)
|
||||
List<Effect> 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<SubtitleStyle> subtitleStyles = subtitleStyleMapper.selectList(null);
|
||||
long styleCount = subtitleStyles.stream().filter(style -> style.getDigitalHumanId().equals(id)).count();
|
||||
assertEquals(0, styleCount);
|
||||
|
||||
// 验证关联的字幕项已删除
|
||||
List<SubtitleItem> subtitleItems = subtitleItemMapper.selectList(null);
|
||||
long subtitleCount = subtitleItems.stream().filter(item -> item.getDigitalHumanId().equals(id)).count();
|
||||
assertEquals(0, subtitleCount);
|
||||
|
||||
// 验证关联的特效已删除
|
||||
List<Effect> effects = effectMapper.selectList(null);
|
||||
long effectCount = effects.stream().filter(effect -> effect.getDigitalHumanId().equals(id)).count();
|
||||
assertEquals(0, effectCount);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<SubtitleStyle> 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<Long> 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);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue