认证服务、广告管理、应用管理service单测剔除真实db使用mock mapper

This commit is contained in:
gaoqr
2026-01-15 11:58:12 +08:00
parent 76a1ad2003
commit 77120e4d3e
6 changed files with 366 additions and 188 deletions
@@ -1,7 +1,7 @@
package com.cf.imes.module.system.service.dict; package com.cf.imes.module.system.service.dict;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.enums.DeletedCodeEnum; import com.cf.imes.framework.common.enums.DeletedCodeEnum;
import com.cf.imes.framework.common.exception.ServiceException; import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.PageResult; import com.cf.imes.framework.common.pojo.PageResult;
@@ -86,11 +86,7 @@ public class DictTypeServiceImpl implements DictTypeService {
// 字典类型发生改变,更新关联字典数据 // 字典类型发生改变,更新关联字典数据
String oldDictTypeDOType = oldDictTypeDO.getType(); String oldDictTypeDOType = oldDictTypeDO.getType();
if (ObjectUtil.notEqual(oldDictTypeDOType, updateReqVOType)) { if (ObjectUtil.notEqual(oldDictTypeDOType, updateReqVOType)) {
UpdateWrapper<DictDataDO> wrapper = new UpdateWrapper<>(); dictDataMapper.update(new LambdaUpdateWrapper<DictDataDO>().set(DictDataDO::getDictType, updateReqVOType).eq(DictDataDO::getDictType, oldDictTypeDOType).eq(DictDataDO::getStatus, DeletedCodeEnum.NOT_DELETED.getStatus()));
wrapper.set("dict_type", updateReqVOType);
wrapper.eq("dict_type", oldDictTypeDOType);
wrapper.eq("status", DeletedCodeEnum.NOT_DELETED.getStatus());
dictDataMapper.update(wrapper);
} }
} }
@@ -82,7 +82,7 @@ public class AdvertisementServiceImpl implements AdvertisementService{
AdvertisementDO advertisementDO = validateAdvertisementExists(id); AdvertisementDO advertisementDO = validateAdvertisementExists(id);
// 发布中的广告不允许编辑 // 发布中的广告不允许编辑
if (advertisementDO.getStatus().equals(AdvertisementStatusEnum.PUBLISHED.getStatus())) { if (AdvertisementStatusEnum.PUBLISHED.getStatus().equals(advertisementDO.getStatus())) {
throw new ServiceException(ADVERTISEMENT_UPDATE_STATUS_ERROR); throw new ServiceException(ADVERTISEMENT_UPDATE_STATUS_ERROR);
} }
@@ -1,38 +1,32 @@
package com.cf.imes.module.system.service.application; package com.cf.imes.module.system.service.application;
import com.cf.imes.framework.test.core.ut.BaseDbAndRedisUnitTest; import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest;
import com.cf.imes.module.system.dal.dataobject.application.ApplicationDO; import com.cf.imes.module.system.dal.dataobject.application.ApplicationDO;
import com.cf.imes.module.system.dal.mysql.application.ApplicationMapper; import com.cf.imes.module.system.dal.mysql.application.ApplicationMapper;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import; import org.mockito.InjectMocks;
import org.mockito.Mock;
import static com.cf.imes.framework.test.core.util.RandomUtils.randomPojo; import static com.cf.imes.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.Mockito.when;
/**
* 应用管理服务单元测试
*
* @author Gqr
* @since 2026/1/13 14:37
*/
@Import(ApplicationServiceImpl.class)
class ApplicationServiceImplTest extends BaseDbAndRedisUnitTest {
@Resource class ApplicationServiceImplTest extends BaseMockitoUnitTest {
@InjectMocks
private ApplicationServiceImpl applicationService; private ApplicationServiceImpl applicationService;
@Resource @Mock
private ApplicationMapper applicationMapper; private ApplicationMapper applicationMapper;
@Test @Test
void getApplicationByOrganId() { void getApplicationByOrganId() {
Long organId = 1L; Long organId = 1L;
ApplicationDO applicationDO = randomPojo(ApplicationDO.class, o -> { ApplicationDO applicationDO = randomPojo(ApplicationDO.class);
o.setOrganId(organId);
});
applicationMapper.insert(applicationDO); applicationMapper.insert(applicationDO);
when(applicationMapper.selectByOrganId(organId)).thenReturn(applicationDO);
ApplicationDO applicationByOrganId = applicationService.getApplicationByOrganId(organId); ApplicationDO applicationByOrganId = applicationService.getApplicationByOrganId(organId);
assertNotNull(applicationByOrganId); assertNotNull(applicationByOrganId);
@@ -9,9 +9,10 @@ import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.ip.core.service.IPQueryService; import com.cf.imes.framework.ip.core.service.IPQueryService;
import com.cf.imes.framework.ip.core.service.dto.IPQueryDataRespDTO; import com.cf.imes.framework.ip.core.service.dto.IPQueryDataRespDTO;
import com.cf.imes.framework.organ.core.service.OrganFrameworkService; import com.cf.imes.framework.organ.core.service.OrganFrameworkService;
import com.cf.imes.framework.security.core.LoginUser;
import com.cf.imes.framework.security.core.service.SecurityFrameworkService; import com.cf.imes.framework.security.core.service.SecurityFrameworkService;
import com.cf.imes.framework.security.test.WithMockLoginUser; import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.framework.test.core.ut.BaseDbUnitTest; import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest;
import com.cf.imes.module.system.api.sms.SmsCodeApi; import com.cf.imes.module.system.api.sms.SmsCodeApi;
import com.cf.imes.module.system.controller.admin.auth.vo.AuthLoginReqVO; import com.cf.imes.module.system.controller.admin.auth.vo.AuthLoginReqVO;
import com.cf.imes.module.system.controller.admin.auth.vo.AuthLoginSmsCheckReqVO; import com.cf.imes.module.system.controller.admin.auth.vo.AuthLoginSmsCheckReqVO;
@@ -36,10 +37,10 @@ import io.jsonwebtoken.security.Keys;
import jakarta.validation.Validator; import jakarta.validation.Validator;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import; import org.mockito.InjectMocks;
import org.mockito.Mock;
import jakarta.annotation.Resource; import org.mockito.MockedStatic;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
@@ -61,58 +62,57 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@Import({AdminAuthServiceImpl.class, ChenfengProperties.class}) class AdminAuthServiceImplTest extends BaseMockitoUnitTest {
public class AdminAuthServiceImplTest extends BaseDbUnitTest {
@Resource @InjectMocks
private AdminAuthServiceImpl authService; private AdminAuthServiceImpl authService;
@MockitoBean @Mock
private AdminUserService userService; private AdminUserService userService;
@MockitoBean @Mock
private CaptchaService captchaService; private CaptchaService captchaService;
@MockitoBean @Mock
private LoginLogService loginLogService; private LoginLogService loginLogService;
@MockitoBean @Mock
private SmsCodeApi smsCodeApi; private SmsCodeApi smsCodeApi;
@MockitoBean @Mock
private OAuth2TokenService oauth2TokenService; private OAuth2TokenService oauth2TokenService;
@MockitoBean @Mock
private OrganService organService; private OrganService organService;
@MockitoBean @Mock
private OrganFrameworkService organFrameworkService; private OrganFrameworkService organFrameworkService;
@MockitoBean @Mock
private SmsCodeService smsCodeService; private SmsCodeService smsCodeService;
@MockitoBean @Mock
private IPQueryService ipQueryService; private IPQueryService ipQueryService;
@MockitoBean @Mock
private TransactionTemplate transactionTemplate; private TransactionTemplate transactionTemplate;
@MockitoBean @Mock
private SecurityFrameworkService securityFrameworkService; private SecurityFrameworkService securityFrameworkService;
@MockitoBean @Mock
private DeptService deptService; private DeptService deptService;
@MockitoBean @Mock
private ProductProperties productProperties; private ProductProperties productProperties;
@MockitoBean @Mock
private JwtProperties jwtProperties; private JwtProperties jwtProperties;
@MockitoBean @Mock
private ChenfengProperties chenfengProperties; private ChenfengProperties chenfengProperties;
@MockitoBean @Mock
private Validator validator; private Validator validator;
private AuthLoginReqVO reqVO; private AuthLoginReqVO reqVO;
@@ -157,7 +157,7 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest {
@Test @Test
void authenticate_passwordNotMatch_throwBadCredentials() { void authenticate_passwordNotMatch_throwBadCredentials() {
AdminUserDO user = new AdminUserDO(); AdminUserDO user = buildUser();
when(userService.getUserUniqueByUserName("admin")) when(userService.getUserUniqueByUserName("admin"))
.thenReturn(user); .thenReturn(user);
@@ -529,7 +529,7 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest {
} }
@Test @Test
public void testLogout_success() { void testLogout_success() {
// 准备参数 // 准备参数
String token = randomString(); String token = randomString();
// mock // mock
@@ -549,7 +549,7 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest {
} }
@Test @Test
public void testLogout_fail() { void testLogout_fail() {
// 准备参数 // 准备参数
String token = randomString(); String token = randomString();
@@ -579,8 +579,14 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest {
} }
@Test @Test
@WithMockLoginUser(userId = 123L, organId = 456L)
void testGetMesJwtToken() { void testGetMesJwtToken() {
// mock 登录用户
LoginUser loginUser = new LoginUser();
loginUser.setId(123L);
loginUser.setOrganId(456L);
try (MockedStatic<SecurityFrameworkUtils> utilities = mockStatic(SecurityFrameworkUtils.class)) {
utilities.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
// mock jwtProperties // mock jwtProperties
when(jwtProperties.getMesTokenTtl()).thenReturn(Duration.ofHours(1)); when(jwtProperties.getMesTokenTtl()).thenReturn(Duration.ofHours(1));
@@ -603,6 +609,7 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest {
assertEquals("test-aud", claims.getAudience()); assertEquals("test-aud", claims.getAudience());
assertNotNull(claims.getExpiration()); assertNotNull(claims.getExpiration());
assertNotNull(claims.getNotBefore()); assertNotNull(claims.getNotBefore());
}
} }
@Test @Test
@@ -1,13 +1,18 @@
package com.cf.imes.module.system.service.dict; package com.cf.imes.module.system.service.dict;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.cf.imes.framework.common.pojo.PageResult; import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest; import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest;
import com.cf.imes.module.system.controller.admin.dict.vo.type.DictTypePageReqVO; import com.cf.imes.module.system.controller.admin.dict.vo.type.DictTypePageReqVO;
import com.cf.imes.module.system.controller.admin.dict.vo.type.DictTypeSaveReqVO; import com.cf.imes.module.system.controller.admin.dict.vo.type.DictTypeSaveReqVO;
import com.cf.imes.module.system.dal.dataobject.dict.DictDataDO;
import com.cf.imes.module.system.dal.dataobject.dict.DictTypeDO; import com.cf.imes.module.system.dal.dataobject.dict.DictTypeDO;
import com.cf.imes.module.system.dal.mysql.dict.DictDataMapper; import com.cf.imes.module.system.dal.mysql.dict.DictDataMapper;
import com.cf.imes.module.system.dal.mysql.dict.DictTypeMapper; import com.cf.imes.module.system.dal.mysql.dict.DictTypeMapper;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
@@ -42,6 +47,11 @@ public class DictTypeServiceImplTest extends BaseMockitoUnitTest {
@Mock @Mock
private DictDataService dictDataService; private DictDataService dictDataService;
@BeforeAll
static void init(){
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), DictDataDO.class);
}
@Test @Test
void testGetDictTypePage_success() { void testGetDictTypePage_success() {
// 准备参数 // 准备参数
@@ -147,13 +157,13 @@ public class DictTypeServiceImplTest extends BaseMockitoUnitTest {
when(dictTypeMapper.selectById(1L)).thenReturn(old); when(dictTypeMapper.selectById(1L)).thenReturn(old);
when(dictTypeMapper.selectByType("new_type")).thenReturn(null); when(dictTypeMapper.selectByType("new_type")).thenReturn(null);
when(dictTypeMapper.updateById(any(DictTypeDO.class))).thenReturn(1); when(dictTypeMapper.updateById(any(DictTypeDO.class))).thenReturn(1);
when(dictDataMapper.update(any(UpdateWrapper.class))).thenReturn(1); when(dictDataMapper.update(any())).thenReturn(1);
dictTypeService.updateDictType(reqVO); dictTypeService.updateDictType(reqVO);
// 校验 dict_data 被批量更新 // 校验 dict_data 被批量更新
verify(dictDataMapper).update( verify(dictDataMapper).update(
argThat((UpdateWrapper wrapper) -> argThat((LambdaUpdateWrapper wrapper) ->
wrapper.getSqlSet().contains("dict_type") wrapper.getSqlSet().contains("dict_type")
) )
); );
@@ -1,7 +1,11 @@
package com.cf.imes.module.system.service.funds.advertisement; package com.cf.imes.module.system.service.funds.advertisement;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.cf.imes.framework.common.pojo.PageResult; import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.test.core.ut.BaseDbClearAfterClassAndRedisUnitTest; import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest;
import com.cf.imes.module.infra.api.file.FileApi; import com.cf.imes.module.infra.api.file.FileApi;
import com.cf.imes.module.system.controller.admin.funds.advertisement.vo.AdvertisementPageReqVO; import com.cf.imes.module.system.controller.admin.funds.advertisement.vo.AdvertisementPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.advertisement.vo.AdvertisementRePublishReqVO; import com.cf.imes.module.system.controller.admin.funds.advertisement.vo.AdvertisementRePublishReqVO;
@@ -11,21 +15,20 @@ import com.cf.imes.module.system.dal.dataobject.funds.advertisement.Advertisemen
import com.cf.imes.module.system.dal.mysql.funds.advertisement.AdvertisementMapper; import com.cf.imes.module.system.dal.mysql.funds.advertisement.AdvertisementMapper;
import com.cf.imes.module.system.enums.advertisement.AdvertisementPositionEnum; import com.cf.imes.module.system.enums.advertisement.AdvertisementPositionEnum;
import com.cf.imes.module.system.enums.advertisement.AdvertisementStatusEnum; import com.cf.imes.module.system.enums.advertisement.AdvertisementStatusEnum;
import jakarta.annotation.Resource; import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder; import org.mockito.ArgumentCaptor;
import org.springframework.context.annotation.Import; import org.mockito.InjectMocks;
import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.mockito.Mock;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.Collections;
import java.util.List; import java.util.List;
import static com.cf.imes.framework.test.core.util.AssertUtils.assertServiceException; import static com.cf.imes.framework.test.core.util.AssertUtils.assertServiceException;
import static com.cf.imes.framework.test.core.util.RandomUtils.randomPojo;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ADVERTISEMENT_IMAGE_EMPTY_ERROR; import static com.cf.imes.module.system.enums.ErrorCodeConstants.ADVERTISEMENT_IMAGE_EMPTY_ERROR;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ADVERTISEMENT_IMAGE_UPLOAD_FAIL; import static com.cf.imes.module.system.enums.ErrorCodeConstants.ADVERTISEMENT_IMAGE_UPLOAD_FAIL;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ADVERTISEMENT_NAME_IS_EXIST; import static com.cf.imes.module.system.enums.ErrorCodeConstants.ADVERTISEMENT_NAME_IS_EXIST;
@@ -34,11 +37,15 @@ import static com.cf.imes.module.system.enums.ErrorCodeConstants.ADVERTISEMENT_N
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ADVERTISEMENT_STATUS_ENDTIME_EXPIRED; import static com.cf.imes.module.system.enums.ErrorCodeConstants.ADVERTISEMENT_STATUS_ENDTIME_EXPIRED;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ADVERTISEMENT_TIME_ERROR; import static com.cf.imes.module.system.enums.ErrorCodeConstants.ADVERTISEMENT_TIME_ERROR;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ADVERTISEMENT_UPDATE_STATUS_ERROR; import static com.cf.imes.module.system.enums.ErrorCodeConstants.ADVERTISEMENT_UPDATE_STATUS_ERROR;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
@@ -49,24 +56,22 @@ import static org.mockito.Mockito.when;
* @author Gqr * @author Gqr
* @since 2025/10/28 10:15 * @since 2025/10/28 10:15
*/ */
@Import(AdvertisementServiceImpl.class) class AdvertisementServiceImplTest extends BaseMockitoUnitTest {
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @InjectMocks
class AdvertisementServiceImplTest extends BaseDbClearAfterClassAndRedisUnitTest { private AdvertisementServiceImpl advertisementService;
@Resource
private AdvertisementService advertisementService;
@Resource @Mock
private AdvertisementMapper advertisementMapper; private AdvertisementMapper advertisementMapper;
@MockitoBean @Mock
private FileApi fileApi; private FileApi fileApi;
private static AdvertisementDO insertedOne; @BeforeAll
static void init(){
private static Long insertTwoId; TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), AdvertisementDO.class);
}
@Test @Test
@Order(1)
void testCreate_whenStartTimeAfterEndTime_shouldThrow() { void testCreate_whenStartTimeAfterEndTime_shouldThrow() {
AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO(); AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO();
reqVO.setStartTime(LocalDate.now().plusDays(1)); reqVO.setStartTime(LocalDate.now().plusDays(1));
@@ -76,47 +81,70 @@ class AdvertisementServiceImplTest extends BaseDbClearAfterClassAndRedisUnitTest
} }
@Test @Test
@Order(2)
void testCreate_whenAdNameExists() { void testCreate_whenAdNameExists() {
// 1. 准备入参(时间必须合法)
AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO(); AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO();
reqVO.setAdName("TestAd");
reqVO.setStartTime(LocalDate.now()); reqVO.setStartTime(LocalDate.now());
reqVO.setEndTime(LocalDate.now().plusDays(1)); reqVO.setEndTime(LocalDate.now().plusDays(1));
reqVO.setAdName("TestAd");
AdvertisementDO existing = randomPojo(AdvertisementDO.class, o -> o.setAdName("TestAd")); // 2. mock:广告名已存在
advertisementMapper.insert(existing); AdvertisementDO exist = new AdvertisementDO();
exist.setId(1L);
exist.setAdName("TestAd");
when(advertisementMapper.selectAdByAdName(
eq("TestAd"),
isNull()
)).thenReturn(exist);
assertServiceException(() -> advertisementService.create(reqVO), ADVERTISEMENT_NAME_IS_EXIST); assertServiceException(() -> advertisementService.create(reqVO), ADVERTISEMENT_NAME_IS_EXIST);
// 4. insert 一定不能被调用
verify(advertisementMapper, never()).insert(any(AdvertisementDO.class));
} }
@Test @Test
@Order(3)
void testCreate_success() { void testCreate_success() {
AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO(); AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO();
reqVO.setStartTime(LocalDate.now()); reqVO.setStartTime(LocalDate.now());
reqVO.setEndTime(LocalDate.now().plusDays(1)); reqVO.setEndTime(LocalDate.now().plusDays(1));
reqVO.setAdName("Ad-CREATE-1"); reqVO.setAdName("Ad-CREATE-1");
reqVO.setAdPosition(List.of(AdvertisementPositionEnum.BASECONFIG_FUNDSQUERY_CAROUSEL.getStatus() reqVO.setAdPosition(List.of(AdvertisementPositionEnum.SYSTEMCONFIG_AMOUNTQUERY_CAROUSEL.getStatus()
, AdvertisementPositionEnum.WORKBENCH_CAROUSEL.getStatus() , AdvertisementPositionEnum.WORKBENCH_CAROUSEL.getStatus()
, AdvertisementPositionEnum.BASECONFIG_FUNDSQUERY_CAROUSEL.getStatus())); , AdvertisementPositionEnum.BASECONFIG_FUNDSQUERY_CAROUSEL.getStatus()));
reqVO.setAdImagePath("https://example.com/image.png"); reqVO.setAdImagePath("https://example.com/image.png");
when(advertisementMapper.selectAdByAdName(eq("Ad-CREATE-1"), isNull()))
.thenReturn(null);
// 3. mock insert:模拟 MyBatis 回填 id
doAnswer(invocation -> {
AdvertisementDO ad = invocation.getArgument(0);
ad.setId(100L);
return 1;
}).when(advertisementMapper).insert(any(AdvertisementDO.class));
// 4. 调用方法
Long id = advertisementService.create(reqVO); Long id = advertisementService.create(reqVO);
insertedOne = advertisementMapper.selectById(id); // 5. 断言返回值
assertEquals(100L, id);
// 验证id // 6. 捕获 insert 的参数,断言字段
assertEquals(insertedOne.getId(), id); ArgumentCaptor<AdvertisementDO> captor =
// 验证 adPosition 去重排序 ArgumentCaptor.forClass(AdvertisementDO.class);
assertEquals(List.of(AdvertisementPositionEnum.WORKBENCH_CAROUSEL.getStatus(), AdvertisementPositionEnum.BASECONFIG_FUNDSQUERY_CAROUSEL.getStatus()), insertedOne.getAdPosition()); verify(advertisementMapper).insert(captor.capture());
// 验证状态
assertEquals(AdvertisementStatusEnum.UNPUBLISHED.getStatus(), insertedOne.getStatus()); AdvertisementDO saved = captor.getValue();
// 验证名称 assertEquals("Ad-CREATE-1", saved.getAdName());
assertEquals("Ad-CREATE-1", insertedOne.getAdName()); assertEquals(AdvertisementStatusEnum.UNPUBLISHED.getStatus(), saved.getStatus());
assertEquals(List.of(AdvertisementPositionEnum.WORKBENCH_CAROUSEL.getStatus()
, AdvertisementPositionEnum.SYSTEMCONFIG_AMOUNTQUERY_CAROUSEL.getStatus()
, AdvertisementPositionEnum.BASECONFIG_FUNDSQUERY_CAROUSEL.getStatus()), saved.getAdPosition());
} }
@Test @Test
@Order(4)
void testUpdate_whenStartTimeAfterEndTime() { void testUpdate_whenStartTimeAfterEndTime() {
AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO(); AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO();
reqVO.setStartTime(LocalDate.now().plusDays(1)); reqVO.setStartTime(LocalDate.now().plusDays(1));
@@ -126,7 +154,6 @@ class AdvertisementServiceImplTest extends BaseDbClearAfterClassAndRedisUnitTest
} }
@Test @Test
@Order(5)
void testUpdate_adExist(){ void testUpdate_adExist(){
AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO(); AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO();
reqVO.setId(123L); reqVO.setId(123L);
@@ -136,174 +163,301 @@ class AdvertisementServiceImplTest extends BaseDbClearAfterClassAndRedisUnitTest
} }
@Test @Test
@Order(5)
void testUpdate_whenAdNameExists() { void testUpdate_whenAdNameExists() {
AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO(); AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO();
reqVO.setStartTime(LocalDate.now()); reqVO.setStartTime(LocalDate.now());
reqVO.setEndTime(LocalDate.now().plusDays(1)); reqVO.setEndTime(LocalDate.now().plusDays(1));
reqVO.setAdName("Ad-CREATE-2"); reqVO.setAdName("Ad-UPDATE-1");
reqVO.setAdPosition(List.of(AdvertisementPositionEnum.BASECONFIG_FUNDSQUERY_CAROUSEL.getStatus()
AdvertisementDO exist = new AdvertisementDO();
when(advertisementMapper.selectOne(any()))
.thenReturn(exist);
when(advertisementMapper.selectAdByAdName(
eq("Ad-UPDATE-1"),
isNull()
)).thenReturn(exist);
assertServiceException(() -> advertisementService.update(reqVO), ADVERTISEMENT_NAME_IS_EXIST);
// 4. insert 一定不能被调用
verify(advertisementMapper, never()).updateById(any(AdvertisementDO.class));
}
@Test
void testUpdate_success() {
// ========== 1. mock:广告已存在 ==========
AdvertisementDO existing = new AdvertisementDO();
existing.setId(1L);
existing.setDeleted(false);
// validateAdvertisementExists() 内部会调用这个
when(advertisementMapper.selectOne(any()))
.thenReturn(existing);
// ========== 2. 构造更新请求 ==========
AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO();
reqVO.setId(1L);
reqVO.setAdName("UpdatedAd");
reqVO.setStartTime(LocalDate.now());
reqVO.setEndTime(LocalDate.now().plusDays(1));
reqVO.setAdPosition(List.of(AdvertisementPositionEnum.SYSTEMCONFIG_AMOUNTQUERY_CAROUSEL.getStatus()
, AdvertisementPositionEnum.WORKBENCH_CAROUSEL.getStatus() , AdvertisementPositionEnum.WORKBENCH_CAROUSEL.getStatus()
, AdvertisementPositionEnum.BASECONFIG_FUNDSQUERY_CAROUSEL.getStatus())); , AdvertisementPositionEnum.BASECONFIG_FUNDSQUERY_CAROUSEL.getStatus()));
reqVO.setAdImagePath("https://example.com/image.png");
insertTwoId = advertisementService.create(reqVO); // ========== 3. 执行 ==========
advertisementService.update(reqVO);
AdvertisementSaveReqVO updateReqVO = new AdvertisementSaveReqVO(); // ========== 4. 验证 updateById 被调用 ==========
updateReqVO.setId(insertedOne.getId()); ArgumentCaptor<AdvertisementDO> captor =
updateReqVO.setStartTime(LocalDate.now()); ArgumentCaptor.forClass(AdvertisementDO.class);
updateReqVO.setEndTime(LocalDate.now().plusDays(1));
updateReqVO.setAdName("Ad-CREATE-2");
assertServiceException(() -> advertisementService.update(updateReqVO), ADVERTISEMENT_NAME_IS_EXIST); verify(advertisementMapper).updateById(captor.capture());
AdvertisementDO updated = captor.getValue();
// ========== 5. 断言关键字段 ==========
assertEquals(1L, updated.getId());
assertEquals("UpdatedAd", updated.getAdName());
} }
@Test @Test
@Order(6)
void testUpdate_success() {
AdvertisementSaveReqVO updateReqVO = new AdvertisementSaveReqVO();
updateReqVO.setId(insertedOne.getId());
updateReqVO.setStartTime(LocalDate.now());
updateReqVO.setEndTime(LocalDate.now().plusDays(1));
updateReqVO.setAdName("Ad-UPDATE-1");
updateReqVO.setAdPosition(List.of(AdvertisementPositionEnum.WORKBENCH_CAROUSEL.getStatus()
, AdvertisementPositionEnum.BASECONFIG_FUNDSQUERY_CAROUSEL.getStatus()));
updateReqVO.setAdImagePath("https://example.com/image.jpg");
advertisementService.update(updateReqVO);
AdvertisementDO db = advertisementMapper.selectById(insertedOne.getId());
assertEquals(db.getAdName(), "Ad-UPDATE-1");
assertEquals(db.getAdPosition(), List.of(AdvertisementPositionEnum.WORKBENCH_CAROUSEL.getStatus()
, AdvertisementPositionEnum.BASECONFIG_FUNDSQUERY_CAROUSEL.getStatus()));
assertEquals(db.getAdImagePath(), "https://example.com/image.jpg");
}
@Test
@Order(7)
void testDelete_notExist() { void testDelete_notExist() {
// mock 不存在
when(advertisementMapper.selectOne(any()))
.thenReturn(null);
assertServiceException(() -> advertisementService.delete(123L), ADVERTISEMENT_NO_EXIST); assertServiceException(() -> advertisementService.delete(123L), ADVERTISEMENT_NO_EXIST);
// 不应该做任何删除
verify(advertisementMapper, never()).deleteById(any());
verify(fileApi, never()).deleteFileByPath(any());
} }
@Test @Test
@Order(8)
void testPublish_notExist(){ void testPublish_notExist(){
assertServiceException(() -> advertisementService.publish(123L), ADVERTISEMENT_NO_EXIST); assertServiceException(() -> advertisementService.publish(123L), ADVERTISEMENT_NO_EXIST);
} }
@Test @Test
@Order(9)
void testUpdate_endTime_success() {
AdvertisementSaveReqVO updateReqVO = new AdvertisementSaveReqVO();
updateReqVO.setId(insertTwoId);
updateReqVO.setStartTime(LocalDate.now().minusDays(5));
updateReqVO.setEndTime(LocalDate.now().minusDays(4));
updateReqVO.setAdName("Ad-UPDATE-2");
updateReqVO.setAdPosition(List.of(AdvertisementPositionEnum.SYSTEMCONFIG_AMOUNTQUERY_CAROUSEL.getStatus()));
assertDoesNotThrow(() -> advertisementService.update(updateReqVO));
}
@Test
@Order(10)
void testPublish_endtime_expired() { void testPublish_endtime_expired() {
assertServiceException(() -> advertisementService.publish(insertTwoId), ADVERTISEMENT_STATUS_ENDTIME_EXPIRED); Long adId = 1L;
AdvertisementDO ad = new AdvertisementDO()
.setId(adId)
.setEndTime(LocalDate.now().minusDays(1));
when(advertisementMapper.selectOne(any(LambdaQueryWrapperX.class))).thenReturn(ad);
assertServiceException(() -> advertisementService.publish(adId), ADVERTISEMENT_STATUS_ENDTIME_EXPIRED);
} }
@Test @Test
@Order(11)
void testPublish_success() { void testPublish_success() {
advertisementService.publish(insertedOne.getId()); Long adId = 1L;
AdvertisementDO db = advertisementMapper.selectById(insertedOne.getId()); AdvertisementDO ad = new AdvertisementDO()
assertEquals(db.getStatus(), AdvertisementStatusEnum.PUBLISHED.getStatus()); .setId(adId)
.setEndTime(LocalDate.now().plusDays(1));
// 模拟 validateAdvertisementExists 返回广告
when(advertisementMapper.selectOne(any())).thenReturn(ad);
advertisementService.publish(adId);
// 验证 update 被调用
verify(advertisementMapper).update(argThat((LambdaUpdateWrapper wrapper) ->
wrapper.getSqlSet().contains("status")
));
} }
@Test @Test
@Order(12)
void testUpdate_published() { void testUpdate_published() {
AdvertisementSaveReqVO updateReqVO = new AdvertisementSaveReqVO(); AdvertisementSaveReqVO updateReqVO = new AdvertisementSaveReqVO();
updateReqVO.setId(insertedOne.getId());
updateReqVO.setStartTime(LocalDate.now()); updateReqVO.setStartTime(LocalDate.now());
updateReqVO.setEndTime(LocalDate.now()); updateReqVO.setEndTime(LocalDate.now());
AdvertisementDO exist = new AdvertisementDO();
exist.setStatus(AdvertisementStatusEnum.PUBLISHED.getStatus());
when(advertisementMapper.selectOne(any()))
.thenReturn(exist);
assertServiceException(() -> advertisementService.update(updateReqVO), ADVERTISEMENT_UPDATE_STATUS_ERROR); assertServiceException(() -> advertisementService.update(updateReqVO), ADVERTISEMENT_UPDATE_STATUS_ERROR);
} }
@Test @Test
@Order(13)
void testDelete_published() { void testDelete_published() {
assertServiceException(() -> advertisementService.delete(insertedOne.getId()), ADVERTISEMENT_NO_DELETE); AdvertisementDO published = new AdvertisementDO();
published.setId(1L);
published.setStatus(AdvertisementStatusEnum.PUBLISHED.getStatus());
published.setAdImagePath("/img/test.png");
when(advertisementMapper.selectOne(any()))
.thenReturn(published);
assertServiceException(() -> advertisementService.delete(1L), ADVERTISEMENT_NO_DELETE);
// 不删除 DB
verify(advertisementMapper, never()).deleteById(any());
// 不删除文件
verify(fileApi, never()).deleteFileByPath(any());
} }
@Test @Test
@Order(14)
void testEndPublish_notExist() { void testEndPublish_notExist() {
assertServiceException(() -> advertisementService.endPublish(null), ADVERTISEMENT_NO_EXIST); assertServiceException(() -> advertisementService.endPublish(null), ADVERTISEMENT_NO_EXIST);
} }
@Test @Test
@Order(15)
void testGet_notExist() { void testGet_notExist() {
assertServiceException(() -> advertisementService.get(123L), ADVERTISEMENT_NO_EXIST); assertServiceException(() -> advertisementService.get(123L), ADVERTISEMENT_NO_EXIST);
} }
@Test @Test
@Order(16)
void testGet() { void testGet() {
assertNotNull(advertisementService.get(insertedOne.getId())); AdvertisementDO ad = new AdvertisementDO();
ad.setId(1L);
ad.setAdName("TestAd");
ad.setStatus(AdvertisementStatusEnum.UNPUBLISHED.getStatus());
when(advertisementMapper.selectOne(any()))
.thenReturn(ad);
AdvertisementRespVO resp = advertisementService.get(1L);
assertNotNull(resp);
assertEquals(ad.getId(), resp.getId());
assertEquals(ad.getAdName(), resp.getAdName());
assertEquals(ad.getStatus(), resp.getStatus());
} }
@Test @Test
@Order(17)
void testGetByPosition() { void testGetByPosition() {
List<AdvertisementRespVO> advertisementRespVOS = advertisementService.getAdvertisementByPosition(AdvertisementPositionEnum.WORKBENCH_CAROUSEL.getStatus()); Integer adPosition = 2;
assertEquals(1, advertisementRespVOS.size());
AdvertisementRespVO vo = new AdvertisementRespVO();
vo.setId(1L);
vo.setAdName("测试广告");
advertisementRespVOS = advertisementService.getAdvertisementByPosition(AdvertisementPositionEnum.SYSTEMCONFIG_AMOUNTQUERY_CAROUSEL.getStatus()); List<AdvertisementRespVO> mockList = List.of(vo);
assertEquals(0, advertisementRespVOS.size());
when(advertisementMapper.selectAdList(
eq(adPosition),
eq(AdvertisementStatusEnum.PUBLISHED.getStatus()),
any(LocalDate.class)
)).thenReturn(mockList);
List<AdvertisementRespVO> result =
advertisementService.getAdvertisementByPosition(adPosition);
assertNotNull(result);
assertEquals(1, result.size());
assertSame(mockList, result);
} }
@Test @Test
@Order(18) void testGetAdvertisementByPosition_empty() {
Integer adPosition = 1;
when(advertisementMapper.selectAdList(
eq(adPosition),
eq(AdvertisementStatusEnum.PUBLISHED.getStatus()),
any(LocalDate.class)
)).thenReturn(Collections.emptyList());
List<AdvertisementRespVO> result =
advertisementService.getAdvertisementByPosition(adPosition);
assertNotNull(result);
assertTrue(result.isEmpty());
}
@Test
void testEndPublish() { void testEndPublish() {
advertisementService.endPublish(insertTwoId); Long adId = 1L;
AdvertisementDO db = advertisementMapper.selectById(insertTwoId); AdvertisementDO ad = new AdvertisementDO().setId(adId);
assertEquals(db.getStatus(), AdvertisementStatusEnum.ENDED.getStatus());
// 模拟 validateAdvertisementExists 返回广告
when(advertisementMapper.selectOne(any())).thenReturn(ad);
advertisementService.endPublish(adId);
// 验证 update 被调用
verify(advertisementMapper).update(argThat((LambdaUpdateWrapper wrapper) ->
wrapper.getSqlSet().contains("status")
));
} }
@Test @Test
@Order(19)
void testGetPage(){ void testGetPage(){
AdvertisementPageReqVO pageReqVO = new AdvertisementPageReqVO(); AdvertisementPageReqVO reqVO = new AdvertisementPageReqVO();
pageReqVO.setStatus(AdvertisementStatusEnum.PUBLISHED.getStatus());
pageReqVO.setAdName("Ad-UPDATE-1");
PageResult<AdvertisementRespVO> page = advertisementService.getPage(pageReqVO); AdvertisementDO ad1 = new AdvertisementDO()
assertEquals(1, page.getTotal()); .setId(1L)
.setAdName("Ad1")
.setStartTime(LocalDate.of(2026, 1, 15))
.setEndTime(LocalDate.of(2026, 1, 16));
pageReqVO.setStatus(AdvertisementStatusEnum.ENDED.getStatus()); AdvertisementDO ad2 = new AdvertisementDO()
pageReqVO.setAdName("Ad-UPDATE-2"); .setId(2L)
page = advertisementService.getPage(pageReqVO); .setAdName("Ad2")
assertEquals(1, page.getTotal()); .setStartTime(LocalDate.of(2026, 1, 17))
.setEndTime(LocalDate.of(2026, 1, 18));
pageReqVO.setStatus(AdvertisementStatusEnum.UNPUBLISHED.getStatus()); PageResult<AdvertisementDO> page = new PageResult<>(List.of(ad1, ad2), 2L);
page = advertisementService.getPage(pageReqVO);
assertEquals(0, page.getTotal()); when(advertisementMapper.selectPage(reqVO)).thenReturn(page);
PageResult<AdvertisementRespVO> result = advertisementService.getPage(reqVO);
assertNotNull(result);
assertEquals(2, result.getList().size());
assertEquals(2L, result.getTotal());
AdvertisementRespVO resp1 = result.getList().get(0);
assertEquals("2026-01-15T00:00~2026-01-16T00:00", resp1.getLaunchTime());
AdvertisementRespVO resp2 = result.getList().get(1);
assertEquals("2026-01-17T00:00~2026-01-18T00:00", resp2.getLaunchTime());
}
@Test
void testGetPage_whenEmpty() {
AdvertisementPageReqVO reqVO = new AdvertisementPageReqVO();
PageResult<AdvertisementDO> emptyPage = new PageResult<>(0L); // total = 0
when(advertisementMapper.selectPage(reqVO)).thenReturn(emptyPage);
PageResult<AdvertisementRespVO> result = advertisementService.getPage(reqVO);
assertNotNull(result);
assertEquals(0, result.getList().size());
assertEquals(0L, result.getTotal());
} }
@Test @Test
@Order(20)
void testDelete_success() { void testDelete_success() {
advertisementService.delete(insertTwoId); AdvertisementDO draft = new AdvertisementDO();
AdvertisementDO db = advertisementMapper.selectById(insertTwoId); draft.setId(1L);
assertNull(db); draft.setStatus(AdvertisementStatusEnum.UNPUBLISHED.getStatus());
draft.setAdImagePath("/img/test.png");
when(advertisementMapper.selectOne(any()))
.thenReturn(draft);
// 执行
advertisementService.delete(1L);
// 删除数据库
verify(advertisementMapper).deleteById(1L);
// 删除文件
verify(fileApi).deleteFileByPath("/img/test.png");
} }
@Test @Test
@Order(21)
void testRepublish_notExist() { void testRepublish_notExist() {
AdvertisementRePublishReqVO reqVO = new AdvertisementRePublishReqVO(); AdvertisementRePublishReqVO reqVO = new AdvertisementRePublishReqVO();
reqVO.setId(null); reqVO.setId(null);
@@ -311,26 +465,43 @@ class AdvertisementServiceImplTest extends BaseDbClearAfterClassAndRedisUnitTest
} }
@Test @Test
@Order(22)
void testRepublish_time_error() { void testRepublish_time_error() {
Long id = 1L;
AdvertisementRePublishReqVO reqVO = new AdvertisementRePublishReqVO(); AdvertisementRePublishReqVO reqVO = new AdvertisementRePublishReqVO();
reqVO.setId(insertedOne.getId()); reqVO.setId(id);
reqVO.setStartTime(LocalDate.now()); reqVO.setStartTime(LocalDate.now().plusDays(5));
reqVO.setEndTime(LocalDate.now().minusDays(1)); reqVO.setEndTime(LocalDate.now());
// 广告存在
when(advertisementMapper.selectOne(any(LambdaQueryWrapperX.class)))
.thenReturn(new AdvertisementDO().setId(id));
assertServiceException(() -> advertisementService.republish(reqVO), ADVERTISEMENT_TIME_ERROR); assertServiceException(() -> advertisementService.republish(reqVO), ADVERTISEMENT_TIME_ERROR);
verify(advertisementMapper, never()).update(any());
} }
@Test @Test
@Order(23)
void testRepublish_success() { void testRepublish_success() {
Long id = 1L;
AdvertisementRePublishReqVO reqVO = new AdvertisementRePublishReqVO(); AdvertisementRePublishReqVO reqVO = new AdvertisementRePublishReqVO();
reqVO.setId(insertedOne.getId()); reqVO.setId(id);
reqVO.setStartTime(LocalDate.now()); reqVO.setStartTime(LocalDate.now());
reqVO.setEndTime(LocalDate.now().plusDays(1)); reqVO.setEndTime(LocalDate.now().plusDays(3));
// mock 广告存在
when(advertisementMapper.selectOne(any(LambdaQueryWrapperX.class)))
.thenReturn(new AdvertisementDO().setId(id));
advertisementService.republish(reqVO); advertisementService.republish(reqVO);
assertEquals(AdvertisementStatusEnum.PUBLISHED.getStatus(), advertisementMapper.selectById(insertedOne.getId()).getStatus());
verify(advertisementMapper).update(argThat((LambdaUpdateWrapper wrapper) ->
wrapper.getSqlSet().contains("status")
&& wrapper.getSqlSet().contains("start_time")
&& wrapper.getSqlSet().contains("end_time")
));
} }
@Test @Test