From 77120e4d3e7195bf00109bf2d64dbeef262b1e5e Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Thu, 15 Jan 2026 11:58:12 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A4=E8=AF=81=E6=9C=8D=E5=8A=A1=E3=80=81?= =?UTF-8?q?=E5=B9=BF=E5=91=8A=E7=AE=A1=E7=90=86=E3=80=81=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E7=AE=A1=E7=90=86service=E5=8D=95=E6=B5=8B=E5=89=94=E9=99=A4?= =?UTF-8?q?=E7=9C=9F=E5=AE=9Edb=E4=BD=BF=E7=94=A8mock=20mapper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/dict/DictTypeServiceImpl.java | 8 +- .../AdvertisementServiceImpl.java | 2 +- .../ApplicationServiceImplTest.java | 26 +- .../auth/AdminAuthServiceImplTest.java | 63 +-- .../service/dict/DictTypeServiceImplTest.java | 16 +- .../AdvertisementServiceImplTest.java | 439 ++++++++++++------ 6 files changed, 366 insertions(+), 188 deletions(-) diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/dict/DictTypeServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/dict/DictTypeServiceImpl.java index 04797dcf0..3ab7a7e47 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/dict/DictTypeServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/dict/DictTypeServiceImpl.java @@ -1,7 +1,7 @@ package com.cf.imes.module.system.service.dict; 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.exception.ServiceException; import com.cf.imes.framework.common.pojo.PageResult; @@ -86,11 +86,7 @@ public class DictTypeServiceImpl implements DictTypeService { // 字典类型发生改变,更新关联字典数据 String oldDictTypeDOType = oldDictTypeDO.getType(); if (ObjectUtil.notEqual(oldDictTypeDOType, updateReqVOType)) { - UpdateWrapper wrapper = new UpdateWrapper<>(); - wrapper.set("dict_type", updateReqVOType); - wrapper.eq("dict_type", oldDictTypeDOType); - wrapper.eq("status", DeletedCodeEnum.NOT_DELETED.getStatus()); - dictDataMapper.update(wrapper); + dictDataMapper.update(new LambdaUpdateWrapper().set(DictDataDO::getDictType, updateReqVOType).eq(DictDataDO::getDictType, oldDictTypeDOType).eq(DictDataDO::getStatus, DeletedCodeEnum.NOT_DELETED.getStatus())); } } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/advertisement/AdvertisementServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/advertisement/AdvertisementServiceImpl.java index 2c0e04d66..38099765e 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/advertisement/AdvertisementServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/advertisement/AdvertisementServiceImpl.java @@ -82,7 +82,7 @@ public class AdvertisementServiceImpl implements AdvertisementService{ 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); } diff --git a/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/application/ApplicationServiceImplTest.java b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/application/ApplicationServiceImplTest.java index fd293dd0a..4e40f9b7e 100644 --- a/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/application/ApplicationServiceImplTest.java +++ b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/application/ApplicationServiceImplTest.java @@ -1,38 +1,32 @@ 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.mysql.application.ApplicationMapper; -import jakarta.annotation.Resource; 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 org.junit.jupiter.api.Assertions.assertEquals; 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; - @Resource + @Mock private ApplicationMapper applicationMapper; @Test void getApplicationByOrganId() { Long organId = 1L; - ApplicationDO applicationDO = randomPojo(ApplicationDO.class, o -> { - o.setOrganId(organId); - }); + ApplicationDO applicationDO = randomPojo(ApplicationDO.class); applicationMapper.insert(applicationDO); + when(applicationMapper.selectByOrganId(organId)).thenReturn(applicationDO); ApplicationDO applicationByOrganId = applicationService.getApplicationByOrganId(organId); assertNotNull(applicationByOrganId); diff --git a/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/auth/AdminAuthServiceImplTest.java b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/auth/AdminAuthServiceImplTest.java index 32351b5f3..c25a8153a 100644 --- a/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/auth/AdminAuthServiceImplTest.java +++ b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/auth/AdminAuthServiceImplTest.java @@ -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.dto.IPQueryDataRespDTO; 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.test.WithMockLoginUser; -import com.cf.imes.framework.test.core.ut.BaseDbUnitTest; +import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils; +import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest; 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.AuthLoginSmsCheckReqVO; @@ -36,10 +37,10 @@ import io.jsonwebtoken.security.Keys; import jakarta.validation.Validator; import org.junit.jupiter.api.BeforeEach; 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.springframework.test.context.bean.override.mockito.MockitoBean; +import org.mockito.MockedStatic; import org.springframework.transaction.TransactionStatus; 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.Mockito.*; -@Import({AdminAuthServiceImpl.class, ChenfengProperties.class}) -public class AdminAuthServiceImplTest extends BaseDbUnitTest { +class AdminAuthServiceImplTest extends BaseMockitoUnitTest { - @Resource + @InjectMocks private AdminAuthServiceImpl authService; - @MockitoBean + @Mock private AdminUserService userService; - @MockitoBean + @Mock private CaptchaService captchaService; - @MockitoBean + @Mock private LoginLogService loginLogService; - @MockitoBean + @Mock private SmsCodeApi smsCodeApi; - @MockitoBean + @Mock private OAuth2TokenService oauth2TokenService; - @MockitoBean + @Mock private OrganService organService; - @MockitoBean + @Mock private OrganFrameworkService organFrameworkService; - @MockitoBean + @Mock private SmsCodeService smsCodeService; - @MockitoBean + @Mock private IPQueryService ipQueryService; - @MockitoBean + @Mock private TransactionTemplate transactionTemplate; - @MockitoBean + @Mock private SecurityFrameworkService securityFrameworkService; - @MockitoBean + @Mock private DeptService deptService; - @MockitoBean + @Mock private ProductProperties productProperties; - @MockitoBean + @Mock private JwtProperties jwtProperties; - @MockitoBean + @Mock private ChenfengProperties chenfengProperties; - @MockitoBean + @Mock private Validator validator; private AuthLoginReqVO reqVO; @@ -157,7 +157,7 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest { @Test void authenticate_passwordNotMatch_throwBadCredentials() { - AdminUserDO user = new AdminUserDO(); + AdminUserDO user = buildUser(); when(userService.getUserUniqueByUserName("admin")) .thenReturn(user); @@ -529,7 +529,7 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest { } @Test - public void testLogout_success() { + void testLogout_success() { // 准备参数 String token = randomString(); // mock @@ -549,7 +549,7 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest { } @Test - public void testLogout_fail() { + void testLogout_fail() { // 准备参数 String token = randomString(); @@ -579,8 +579,14 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest { } @Test - @WithMockLoginUser(userId = 123L, organId = 456L) void testGetMesJwtToken() { + // mock 登录用户 + LoginUser loginUser = new LoginUser(); + loginUser.setId(123L); + loginUser.setOrganId(456L); + + try (MockedStatic utilities = mockStatic(SecurityFrameworkUtils.class)) { + utilities.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); // mock jwtProperties when(jwtProperties.getMesTokenTtl()).thenReturn(Duration.ofHours(1)); @@ -603,6 +609,7 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest { assertEquals("test-aud", claims.getAudience()); assertNotNull(claims.getExpiration()); assertNotNull(claims.getNotBefore()); + } } @Test diff --git a/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/dict/DictTypeServiceImplTest.java b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/dict/DictTypeServiceImplTest.java index 7d942f8f8..7418854ef 100644 --- a/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/dict/DictTypeServiceImplTest.java +++ b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/dict/DictTypeServiceImplTest.java @@ -1,13 +1,18 @@ 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.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.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.mysql.dict.DictDataMapper; 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.mockito.InjectMocks; import org.mockito.Mock; @@ -42,6 +47,11 @@ public class DictTypeServiceImplTest extends BaseMockitoUnitTest { @Mock private DictDataService dictDataService; + @BeforeAll + static void init(){ + TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), DictDataDO.class); + } + @Test void testGetDictTypePage_success() { // 准备参数 @@ -147,13 +157,13 @@ public class DictTypeServiceImplTest extends BaseMockitoUnitTest { when(dictTypeMapper.selectById(1L)).thenReturn(old); when(dictTypeMapper.selectByType("new_type")).thenReturn(null); 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); // 校验 dict_data 被批量更新 verify(dictDataMapper).update( - argThat((UpdateWrapper wrapper) -> + argThat((LambdaUpdateWrapper wrapper) -> wrapper.getSqlSet().contains("dict_type") ) ); diff --git a/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/funds/advertisement/AdvertisementServiceImplTest.java b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/funds/advertisement/AdvertisementServiceImplTest.java index 47b822731..ea4dd4345 100644 --- a/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/funds/advertisement/AdvertisementServiceImplTest.java +++ b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/funds/advertisement/AdvertisementServiceImplTest.java @@ -1,7 +1,11 @@ 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.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.system.controller.admin.funds.advertisement.vo.AdvertisementPageReqVO; 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.enums.advertisement.AdvertisementPositionEnum; import com.cf.imes.module.system.enums.advertisement.AdvertisementStatusEnum; -import jakarta.annotation.Resource; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; +import org.apache.ibatis.builder.MapperBuilderAssistant; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import org.springframework.context.annotation.Import; -import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.time.LocalDate; +import java.util.Collections; import java.util.List; 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_UPLOAD_FAIL; 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_TIME_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.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.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.never; import static org.mockito.Mockito.times; @@ -49,24 +56,22 @@ import static org.mockito.Mockito.when; * @author Gqr * @since 2025/10/28 10:15 */ -@Import(AdvertisementServiceImpl.class) -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -class AdvertisementServiceImplTest extends BaseDbClearAfterClassAndRedisUnitTest { - @Resource - private AdvertisementService advertisementService; +class AdvertisementServiceImplTest extends BaseMockitoUnitTest { + @InjectMocks + private AdvertisementServiceImpl advertisementService; - @Resource + @Mock private AdvertisementMapper advertisementMapper; - @MockitoBean + @Mock private FileApi fileApi; - private static AdvertisementDO insertedOne; - - private static Long insertTwoId; + @BeforeAll + static void init(){ + TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), AdvertisementDO.class); + } @Test - @Order(1) void testCreate_whenStartTimeAfterEndTime_shouldThrow() { AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO(); reqVO.setStartTime(LocalDate.now().plusDays(1)); @@ -76,47 +81,70 @@ class AdvertisementServiceImplTest extends BaseDbClearAfterClassAndRedisUnitTest } @Test - @Order(2) void testCreate_whenAdNameExists() { + // 1. 准备入参(时间必须合法) AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO(); + reqVO.setAdName("TestAd"); reqVO.setStartTime(LocalDate.now()); reqVO.setEndTime(LocalDate.now().plusDays(1)); - reqVO.setAdName("TestAd"); - AdvertisementDO existing = randomPojo(AdvertisementDO.class, o -> o.setAdName("TestAd")); - advertisementMapper.insert(existing); + // 2. mock:广告名已存在 + 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); + + // 4. insert 一定不能被调用 + verify(advertisementMapper, never()).insert(any(AdvertisementDO.class)); } @Test - @Order(3) void testCreate_success() { AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO(); reqVO.setStartTime(LocalDate.now()); reqVO.setEndTime(LocalDate.now().plusDays(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.BASECONFIG_FUNDSQUERY_CAROUSEL.getStatus())); 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); - insertedOne = advertisementMapper.selectById(id); + // 5. 断言返回值 + assertEquals(100L, id); - // 验证id - assertEquals(insertedOne.getId(), id); - // 验证 adPosition 去重排序 - assertEquals(List.of(AdvertisementPositionEnum.WORKBENCH_CAROUSEL.getStatus(), AdvertisementPositionEnum.BASECONFIG_FUNDSQUERY_CAROUSEL.getStatus()), insertedOne.getAdPosition()); - // 验证状态 - assertEquals(AdvertisementStatusEnum.UNPUBLISHED.getStatus(), insertedOne.getStatus()); - // 验证名称 - assertEquals("Ad-CREATE-1", insertedOne.getAdName()); + // 6. 捕获 insert 的参数,断言字段 + ArgumentCaptor captor = + ArgumentCaptor.forClass(AdvertisementDO.class); + verify(advertisementMapper).insert(captor.capture()); + + AdvertisementDO saved = captor.getValue(); + assertEquals("Ad-CREATE-1", saved.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 - @Order(4) void testUpdate_whenStartTimeAfterEndTime() { AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO(); reqVO.setStartTime(LocalDate.now().plusDays(1)); @@ -126,7 +154,6 @@ class AdvertisementServiceImplTest extends BaseDbClearAfterClassAndRedisUnitTest } @Test - @Order(5) void testUpdate_adExist(){ AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO(); reqVO.setId(123L); @@ -136,174 +163,301 @@ class AdvertisementServiceImplTest extends BaseDbClearAfterClassAndRedisUnitTest } @Test - @Order(5) void testUpdate_whenAdNameExists() { AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO(); reqVO.setStartTime(LocalDate.now()); reqVO.setEndTime(LocalDate.now().plusDays(1)); - reqVO.setAdName("Ad-CREATE-2"); - reqVO.setAdPosition(List.of(AdvertisementPositionEnum.BASECONFIG_FUNDSQUERY_CAROUSEL.getStatus() + reqVO.setAdName("Ad-UPDATE-1"); + + 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.BASECONFIG_FUNDSQUERY_CAROUSEL.getStatus())); - reqVO.setAdImagePath("https://example.com/image.png"); - insertTwoId = advertisementService.create(reqVO); + // ========== 3. 执行 ========== + advertisementService.update(reqVO); - AdvertisementSaveReqVO updateReqVO = new AdvertisementSaveReqVO(); - updateReqVO.setId(insertedOne.getId()); - updateReqVO.setStartTime(LocalDate.now()); - updateReqVO.setEndTime(LocalDate.now().plusDays(1)); - updateReqVO.setAdName("Ad-CREATE-2"); + // ========== 4. 验证 updateById 被调用 ========== + ArgumentCaptor captor = + ArgumentCaptor.forClass(AdvertisementDO.class); - 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 - @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() { + // mock 不存在 + when(advertisementMapper.selectOne(any())) + .thenReturn(null); + assertServiceException(() -> advertisementService.delete(123L), ADVERTISEMENT_NO_EXIST); + + // 不应该做任何删除 + verify(advertisementMapper, never()).deleteById(any()); + verify(fileApi, never()).deleteFileByPath(any()); } @Test - @Order(8) void testPublish_notExist(){ assertServiceException(() -> advertisementService.publish(123L), ADVERTISEMENT_NO_EXIST); } @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() { - 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 - @Order(11) void testPublish_success() { - advertisementService.publish(insertedOne.getId()); + Long adId = 1L; - AdvertisementDO db = advertisementMapper.selectById(insertedOne.getId()); - assertEquals(db.getStatus(), AdvertisementStatusEnum.PUBLISHED.getStatus()); + AdvertisementDO ad = new AdvertisementDO() + .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 - @Order(12) void testUpdate_published() { AdvertisementSaveReqVO updateReqVO = new AdvertisementSaveReqVO(); - updateReqVO.setId(insertedOne.getId()); updateReqVO.setStartTime(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); } @Test - @Order(13) 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 - @Order(14) void testEndPublish_notExist() { assertServiceException(() -> advertisementService.endPublish(null), ADVERTISEMENT_NO_EXIST); } @Test - @Order(15) void testGet_notExist() { assertServiceException(() -> advertisementService.get(123L), ADVERTISEMENT_NO_EXIST); } @Test - @Order(16) 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 - @Order(17) void testGetByPosition() { - List advertisementRespVOS = advertisementService.getAdvertisementByPosition(AdvertisementPositionEnum.WORKBENCH_CAROUSEL.getStatus()); - assertEquals(1, advertisementRespVOS.size()); + Integer adPosition = 2; + AdvertisementRespVO vo = new AdvertisementRespVO(); + vo.setId(1L); + vo.setAdName("测试广告"); - advertisementRespVOS = advertisementService.getAdvertisementByPosition(AdvertisementPositionEnum.SYSTEMCONFIG_AMOUNTQUERY_CAROUSEL.getStatus()); - assertEquals(0, advertisementRespVOS.size()); + List mockList = List.of(vo); + + when(advertisementMapper.selectAdList( + eq(adPosition), + eq(AdvertisementStatusEnum.PUBLISHED.getStatus()), + any(LocalDate.class) + )).thenReturn(mockList); + + List result = + advertisementService.getAdvertisementByPosition(adPosition); + + assertNotNull(result); + assertEquals(1, result.size()); + assertSame(mockList, result); } @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 result = + advertisementService.getAdvertisementByPosition(adPosition); + + assertNotNull(result); + assertTrue(result.isEmpty()); + } + + + @Test void testEndPublish() { - advertisementService.endPublish(insertTwoId); + Long adId = 1L; - AdvertisementDO db = advertisementMapper.selectById(insertTwoId); - assertEquals(db.getStatus(), AdvertisementStatusEnum.ENDED.getStatus()); + AdvertisementDO ad = new AdvertisementDO().setId(adId); + + // 模拟 validateAdvertisementExists 返回广告 + when(advertisementMapper.selectOne(any())).thenReturn(ad); + + advertisementService.endPublish(adId); + + // 验证 update 被调用 + verify(advertisementMapper).update(argThat((LambdaUpdateWrapper wrapper) -> + wrapper.getSqlSet().contains("status") + )); } @Test - @Order(19) void testGetPage(){ - AdvertisementPageReqVO pageReqVO = new AdvertisementPageReqVO(); - pageReqVO.setStatus(AdvertisementStatusEnum.PUBLISHED.getStatus()); - pageReqVO.setAdName("Ad-UPDATE-1"); + AdvertisementPageReqVO reqVO = new AdvertisementPageReqVO(); - PageResult page = advertisementService.getPage(pageReqVO); - assertEquals(1, page.getTotal()); + AdvertisementDO ad1 = new AdvertisementDO() + .setId(1L) + .setAdName("Ad1") + .setStartTime(LocalDate.of(2026, 1, 15)) + .setEndTime(LocalDate.of(2026, 1, 16)); - pageReqVO.setStatus(AdvertisementStatusEnum.ENDED.getStatus()); - pageReqVO.setAdName("Ad-UPDATE-2"); - page = advertisementService.getPage(pageReqVO); - assertEquals(1, page.getTotal()); + AdvertisementDO ad2 = new AdvertisementDO() + .setId(2L) + .setAdName("Ad2") + .setStartTime(LocalDate.of(2026, 1, 17)) + .setEndTime(LocalDate.of(2026, 1, 18)); - pageReqVO.setStatus(AdvertisementStatusEnum.UNPUBLISHED.getStatus()); - page = advertisementService.getPage(pageReqVO); - assertEquals(0, page.getTotal()); + PageResult page = new PageResult<>(List.of(ad1, ad2), 2L); + + when(advertisementMapper.selectPage(reqVO)).thenReturn(page); + + PageResult 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 emptyPage = new PageResult<>(0L); // total = 0 + when(advertisementMapper.selectPage(reqVO)).thenReturn(emptyPage); + + PageResult result = advertisementService.getPage(reqVO); + + assertNotNull(result); + assertEquals(0, result.getList().size()); + assertEquals(0L, result.getTotal()); } @Test - @Order(20) void testDelete_success() { - advertisementService.delete(insertTwoId); - AdvertisementDO db = advertisementMapper.selectById(insertTwoId); - assertNull(db); + AdvertisementDO draft = new AdvertisementDO(); + draft.setId(1L); + 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 - @Order(21) void testRepublish_notExist() { AdvertisementRePublishReqVO reqVO = new AdvertisementRePublishReqVO(); reqVO.setId(null); @@ -311,26 +465,43 @@ class AdvertisementServiceImplTest extends BaseDbClearAfterClassAndRedisUnitTest } @Test - @Order(22) void testRepublish_time_error() { + Long id = 1L; + AdvertisementRePublishReqVO reqVO = new AdvertisementRePublishReqVO(); - reqVO.setId(insertedOne.getId()); - reqVO.setStartTime(LocalDate.now()); - reqVO.setEndTime(LocalDate.now().minusDays(1)); + reqVO.setId(id); + reqVO.setStartTime(LocalDate.now().plusDays(5)); + reqVO.setEndTime(LocalDate.now()); + + // 广告存在 + when(advertisementMapper.selectOne(any(LambdaQueryWrapperX.class))) + .thenReturn(new AdvertisementDO().setId(id)); assertServiceException(() -> advertisementService.republish(reqVO), ADVERTISEMENT_TIME_ERROR); + + verify(advertisementMapper, never()).update(any()); } @Test - @Order(23) void testRepublish_success() { + Long id = 1L; + AdvertisementRePublishReqVO reqVO = new AdvertisementRePublishReqVO(); - reqVO.setId(insertedOne.getId()); + reqVO.setId(id); 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); - 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