1、WithMockLoginUser从Security上下文改为纯mock;2、更新资金管理service剥离真实h2db,采用纯mock;

This commit is contained in:
gaoqr
2026-01-20 14:44:20 +08:00
parent 77120e4d3e
commit 000561171a
13 changed files with 1034 additions and 1312 deletions
@@ -434,7 +434,7 @@ public class InvoiceServiceImpl implements InvoiceService {
* @return
*/
private List<PurchaseRecordDO> validatePurchaseRecordExists(List<Long> purchaseId) {
List<PurchaseRecordDO> purchaseRecordDOS = purchaseRecordMapper.selectBatchIds(purchaseId);
List<PurchaseRecordDO> purchaseRecordDOS = purchaseRecordMapper.selectByIds(purchaseId);
if (CollUtil.isEmpty(purchaseRecordDOS)) {
throw new ServiceException(PURCHASE_RECORD_NO_EXIST);
}
@@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.mybatis.core.query.LambdaUpdateWrapperX;
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductPageReqVO;
@@ -65,8 +64,6 @@ public class ProductsServiceImpl implements ProductsService {
if (ProductStatusEnum.PRODUCT_UPDATES.getStatus().equals(status) && !ProductStatusEnum.isProductDelis(updateReqVOStatus)) {
throw new ServiceException(PRODUCTS_NO_UPDATE);
}
ProductsDO productsDO = BeanUtils.toBean(updateReqVO, ProductsDO.class);
productsMapper.updateById(productsDO);
productsMapper.update(new LambdaUpdateWrapperX<ProductsDO>()
.eq(ProductsDO::getId, updateReqVOId)
.setIfPresent(ProductsDO::getProductName, productName)
@@ -0,0 +1,54 @@
package com.cf.imes.module.system.common;
import com.cf.imes.framework.security.core.LoginUser;
import com.cf.imes.framework.security.test.WithMockLoginUser;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.mockito.Mockito;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
/**
*
*
* @author Gqr
* @since 2026/1/16 10:20
*/
public class WithMockLoginUserExtension implements BeforeEachCallback, AfterEachCallback {
@Override
public void afterEach(ExtensionContext context) {
SecurityContextHolder.clearContext();
}
@Override
public void beforeEach(ExtensionContext context) {
WithMockLoginUser ann = findAnnotation(context);
LoginUser loginUser = new LoginUser();
if (ann != null) {
loginUser.setId(ann.userId());
loginUser.setOrganId(ann.organId());
loginUser.setDeptId(ann.deptId());
loginUser.setNickname(ann.username());
} else {
return;
}
Authentication authentication = Mockito.mock(Authentication.class);
Mockito.when(authentication.getPrincipal()).thenReturn(loginUser);
SecurityContext securityContext = Mockito.mock(SecurityContext.class);
Mockito.when(securityContext.getAuthentication())
.thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);
}
private WithMockLoginUser findAnnotation(ExtensionContext context) {
return context.getElement()
.map(el -> el.getAnnotation(WithMockLoginUser.class))
.orElse(null);
}
}
@@ -1,7 +1,10 @@
package com.cf.imes.module.system.service.funds.delay;
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.BaseDbAndRedisUnitTest;
import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest;
import com.cf.imes.module.system.controller.admin.funds.delay.vo.PreviouProductDelayRespVO;
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelayPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelayRespVO;
@@ -12,481 +15,353 @@ import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
import com.cf.imes.module.system.dal.mysql.funds.delay.ProductDelayRecordMapper;
import com.cf.imes.module.system.dal.mysql.funds.purchase.PurchaseRecordMapper;
import com.cf.imes.module.system.enums.pay.DurationUnitEnum;
import com.cf.imes.module.system.enums.pay.PayChannelCodeEnum;
import com.cf.imes.module.system.enums.pay.PurchaseRecordStatusEnum;
import com.cf.imes.module.system.service.funds.products.ProductsDetailService;
import com.cf.imes.module.system.service.funds.purchase.PurchaseService;
import com.cf.imes.module.system.service.organ.OrganService;
import jakarta.annotation.Resource;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.time.LocalDate;
import java.util.Arrays;
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.randomLongId;
import static com.cf.imes.framework.test.core.util.RandomUtils.randomPojo;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCT_DELAY_UNIT_NOT_SUPPORT;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCT_PURCHASE_NO_EXIST;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
/**
* {@link ProductDelayServiceImpl} 的单元测试类
*
* @author Gqr
* @since 2025/12/8 14:30
*/
@Import(ProductDelayServiceImpl.class)
public class ProductDelayServiceImplTest extends BaseDbAndRedisUnitTest {
class ProductDelayServiceImplTest extends BaseMockitoUnitTest {
@Resource
@InjectMocks
private ProductDelayServiceImpl productDelayService;
@Resource
private ProductDelayRecordMapper recordMapper;
@Mock
private ProductDelayRecordMapper productDelayRecordMapper;
@Resource
@Mock
private PurchaseRecordMapper purchaseRecordMapper;
@MockitoBean
@Mock
private OrganService organService;
@MockitoBean
@Mock
private PurchaseService purchaseService;
@MockitoBean
private ProductsDetailService productsDetailService;
@Test
public void testCreateProductDelay_noPreDelayRecord_success() {
// 准备参数
Long organId = randomLongId();
Long purchaseId = randomLongId();
Long productId = randomLongId();
// Mock 组织
OrganizationDO organization = new OrganizationDO();
organization.setId(organId);
organization.setName("测试组织");
when(organService.validOrgan(organId)).thenReturn(organization);
// Mock 购买记录
PurchaseRecordDO purchaseRecord = PurchaseRecordDO.builder()
.id(purchaseId)
.productId(productId)
.productName("测试产品")
.startTime(LocalDate.now().minusMonths(6))
.endTime(LocalDate.now().plusMonths(6))
.build();
when(purchaseService.getRecord(purchaseId)).thenReturn(purchaseRecord);
// 构造请求
ProductDelaySaveReqVO reqVO = new ProductDelaySaveReqVO();
reqVO.setOrganId(organId);
reqVO.setPurchaseId(purchaseId);
reqVO.setDelayDuration(3);
reqVO.setDelayDurationUnit(DurationUnitEnum.MONTH.getCode());
// 调用
Long delayId = productDelayService.createProductDelay(reqVO);
// 断言
assertNotNull(delayId);
ProductDelayRecordDO dbRecord = recordMapper.selectById(delayId);
assertNotNull(dbRecord);
assertEquals(organId, dbRecord.getOrganId());
assertEquals("测试组织", dbRecord.getOrganName());
assertEquals(productId, dbRecord.getProductId());
assertEquals("测试产品", dbRecord.getProductName());
assertEquals(3, dbRecord.getDelayDuration());
assertEquals(DurationUnitEnum.MONTH.getCode(), dbRecord.getDelayDurationUnit());
assertEquals(purchaseRecord.getEndTime(), dbRecord.getEndTime());
assertEquals(purchaseRecord.getEndTime().plusMonths(3), dbRecord.getDelayTime());
assertEquals(purchaseId, dbRecord.getPurchaseId());
assertFalse(dbRecord.getPaid());
@BeforeAll
static void init(){
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), ProductDelayRecordDO.class);
}
@Test
public void testCreateProductDelay_withPreDelayRecord_success() {
// 准备参数
Long organId = randomLongId();
Long purchaseId = randomLongId();
Long productId = randomLongId();
// Mock 组织
OrganizationDO organization = new OrganizationDO();
organization.setId(organId);
organization.setName("测试组织");
when(organService.validOrgan(organId)).thenReturn(organization);
// Mock 购买记录
PurchaseRecordDO purchaseRecord = PurchaseRecordDO.builder()
.id(purchaseId)
.productId(productId)
.productName("测试产品")
.startTime(LocalDate.now().minusMonths(6))
.endTime(LocalDate.now().plusMonths(6))
.build();
when(purchaseService.getRecord(purchaseId)).thenReturn(purchaseRecord);
// 插入前序延期记录
ProductDelayRecordDO preDelayRecord = ProductDelayRecordDO.builder()
.organId(organId)
.organName("测试组织")
.productId(productId)
.productName("测试产品")
.delayDuration(1)
.delayDurationUnit(DurationUnitEnum.YEAR.getCode())
.endTime(purchaseRecord.getEndTime())
.delayTime(purchaseRecord.getEndTime().plusYears(1))
.purchaseId(purchaseId)
.paid(true)
.build();
recordMapper.insert(preDelayRecord);
// 构造请求
void testCreateProductDelay_purchaseNotExist() {
ProductDelaySaveReqVO reqVO = new ProductDelaySaveReqVO();
reqVO.setOrganId(organId);
reqVO.setPurchaseId(purchaseId);
reqVO.setDelayDuration(6);
reqVO.setDelayDurationUnit(DurationUnitEnum.YEAR.getCode());
reqVO.setOrganId(1L);
reqVO.setPurchaseId(10L);
// 调用
Long delayId = productDelayService.createProductDelay(reqVO);
when(organService.validOrgan(1L)).thenReturn(new OrganizationDO());
when(purchaseService.getRecord(10L)).thenReturn(null);
// 断言
assertNotNull(delayId);
ProductDelayRecordDO dbRecord = recordMapper.selectById(delayId);
assertNotNull(dbRecord);
// 应该基于前序记录的延期时间计算
assertEquals(preDelayRecord.getDelayTime(), dbRecord.getEndTime());
assertEquals(preDelayRecord.getDelayTime().plusYears(6), dbRecord.getDelayTime());
assertServiceException(() -> productDelayService.createProductDelay(reqVO), PRODUCT_PURCHASE_NO_EXIST);
}
@Test
public void testCreateProductDelay_expiredEndTime_success() {
// 准备参数
Long organId = randomLongId();
Long purchaseId = randomLongId();
Long productId = randomLongId();
void testCreateProductDelay_success_noLastDelay_notExpired() {
LocalDate now = LocalDate.now();
// Mock 组织
OrganizationDO organization = new OrganizationDO();
organization.setId(organId);
organization.setName("测试组织");
when(organService.validOrgan(organId)).thenReturn(organization);
// Mock 购买记录(已过期)
PurchaseRecordDO purchaseRecord = PurchaseRecordDO.builder()
.id(purchaseId)
.productId(productId)
.productName("测试产品")
.startTime(LocalDate.now().minusMonths(12))
.endTime(LocalDate.now().minusMonths(1)) // 已过期
.build();
when(purchaseService.getRecord(purchaseId)).thenReturn(purchaseRecord);
// 构造请求
ProductDelaySaveReqVO reqVO = new ProductDelaySaveReqVO();
reqVO.setOrganId(organId);
reqVO.setPurchaseId(purchaseId);
reqVO.setDelayDuration(3);
reqVO.setOrganId(1L);
reqVO.setPurchaseId(100L);
reqVO.setDelayDuration(10);
reqVO.setDelayDurationUnit(DurationUnitEnum.DAY.getCode());
// 调用
Long delayId = productDelayService.createProductDelay(reqVO);
OrganizationDO org = new OrganizationDO();
org.setName("组织A");
// 断言
assertNotNull(delayId);
ProductDelayRecordDO dbRecord = recordMapper.selectById(delayId);
assertNotNull(dbRecord);
// 已过期的情况,应该从今天开始计算
assertEquals(LocalDate.now(), dbRecord.getEndTime());
assertEquals(LocalDate.now().plusDays(3), dbRecord.getDelayTime());
PurchaseRecordDO purchase = new PurchaseRecordDO();
purchase.setProductId(11L);
purchase.setProductName("产品A");
purchase.setEndTime(now.plusDays(5));
when(organService.validOrgan(1L)).thenReturn(org);
when(purchaseService.getRecord(100L)).thenReturn(purchase);
when(productDelayRecordMapper.selectOne(any())).thenReturn(null);
productDelayService.createProductDelay(reqVO);
verify(productDelayRecordMapper).insert(argThat((ProductDelayRecordDO recordDO) ->
recordDO.getEndTime().equals(purchase.getEndTime())
&& recordDO.getDelayTime().equals(purchase.getEndTime().plusDays(10))
&& !recordDO.getPaid()
));
}
@Test
public void testCreateProductDelay_withExpiredPreDelayRecord_success() {
// 准备参数
Long organId = randomLongId();
Long purchaseId = randomLongId();
Long productId = randomLongId();
void testCreateProductDelay_success_purchaseExpired() {
LocalDate now = LocalDate.now();
// Mock 组织
OrganizationDO organization = new OrganizationDO();
organization.setId(organId);
organization.setName("测试组织");
when(organService.validOrgan(organId)).thenReturn(organization);
// Mock 购买记录(未过期)
PurchaseRecordDO purchaseRecord = PurchaseRecordDO.builder()
.id(purchaseId)
.productId(productId)
.productName("测试产品")
.startTime(LocalDate.now().minusMonths(6))
.endTime(LocalDate.now().plusMonths(6))
.build();
when(purchaseService.getRecord(purchaseId)).thenReturn(purchaseRecord);
// 插入前序延期记录(延期时间未过期)
ProductDelayRecordDO preDelayRecord = ProductDelayRecordDO.builder()
.organId(organId)
.organName("测试组织")
.productId(productId)
.productName("测试产品")
.delayDuration(3)
.delayDurationUnit(DurationUnitEnum.MONTH.getCode())
.endTime(purchaseRecord.getEndTime())
.delayTime(LocalDate.now().plusMonths(9)) // 未过期的延期时间
.purchaseId(purchaseId)
.paid(true)
.build();
recordMapper.insert(preDelayRecord);
// 构造请求
ProductDelaySaveReqVO reqVO = new ProductDelaySaveReqVO();
reqVO.setOrganId(organId);
reqVO.setPurchaseId(purchaseId);
reqVO.setDelayDuration(6);
reqVO.setDelayDurationUnit(4);
// 调用并断言异常
assertServiceException(() -> productDelayService.createProductDelay(reqVO),
PRODUCT_DELAY_UNIT_NOT_SUPPORT);
}
@Test
public void testCreateProductDelay_purchaseNotExist() {
// 准备参数
Long organId = randomLongId();
Long purchaseId = randomLongId();
// Mock 组织
OrganizationDO organization = new OrganizationDO();
organization.setId(organId);
organization.setName("测试组织");
when(organService.validOrgan(organId)).thenReturn(organization);
// Mock 购买记录不存在
when(purchaseService.getRecord(purchaseId)).thenReturn(null);
// 构造请求
ProductDelaySaveReqVO reqVO = new ProductDelaySaveReqVO();
reqVO.setOrganId(organId);
reqVO.setPurchaseId(purchaseId);
reqVO.setDelayDuration(3);
reqVO.setOrganId(1L);
reqVO.setPurchaseId(200L);
reqVO.setDelayDuration(1);
reqVO.setDelayDurationUnit(DurationUnitEnum.MONTH.getCode());
// 调用并断言异常
assertServiceException(() -> productDelayService.createProductDelay(reqVO),
PRODUCT_PURCHASE_NO_EXIST);
when(organService.validOrgan(any())).thenReturn(new OrganizationDO());
when(purchaseService.getRecord(any())).thenReturn(
PurchaseRecordDO.builder()
.productId(1L)
.productName("产品")
.endTime(now.minusDays(3))
.build()
);
when(productDelayRecordMapper.selectOne(any())).thenReturn(null);
productDelayService.createProductDelay(reqVO);
verify(productDelayRecordMapper).insert(argThat((ProductDelayRecordDO r) ->
r.getEndTime().equals(now)
&& r.getDelayTime().equals(now.plusMonths(1))
));
}
@Test
void testCreateProductDelay_success_withLastDelay() {
LocalDate base = LocalDate.now().plusDays(5);
when(productDelayRecordMapper.selectOne(any()))
.thenReturn(ProductDelayRecordDO.builder()
.delayTime(base)
.build());
when(organService.validOrgan(any())).thenReturn(new OrganizationDO());
when(purchaseService.getRecord(any())).thenReturn(
PurchaseRecordDO.builder()
.productId(1L)
.productName("产品")
.endTime(LocalDate.now())
.build()
);
ProductDelaySaveReqVO reqVO = new ProductDelaySaveReqVO();
reqVO.setOrganId(1L);
reqVO.setPurchaseId(1L);
reqVO.setDelayDuration(2);
reqVO.setDelayDurationUnit(DurationUnitEnum.YEAR.getCode());
productDelayService.createProductDelay(reqVO);
verify(productDelayRecordMapper).insert(argThat((ProductDelayRecordDO r) ->
r.getEndTime().equals(base)
&& r.getDelayTime().equals(base.plusYears(2))
));
}
@Test
public void testGetPage() {
// mock 数据
ProductDelayRecordDO record1 = randomPojo(ProductDelayRecordDO.class, o -> {
o.setOrganName("晨丰科技");
o.setProductName("ERP产品");
o.setDelayDuration(3);
o.setDelayDurationUnit(DurationUnitEnum.MONTH.getCode());
});
recordMapper.insert(record1);
void testCreateProductDelay_unitNotSupport() {
ProductDelaySaveReqVO reqVO = new ProductDelaySaveReqVO();
reqVO.setOrganId(1L);
reqVO.setPurchaseId(1L);
reqVO.setDelayDuration(1);
reqVO.setDelayDurationUnit(999); // 非法
// 不匹配的数据
recordMapper.insert(randomPojo(ProductDelayRecordDO.class, o -> {
o.setOrganName("其他组织");
o.setProductName("ERP产品");
o.setDelayDuration(4);
o.setDelayDurationUnit(DurationUnitEnum.MONTH.getCode());
}));
when(organService.validOrgan(any())).thenReturn(new OrganizationDO());
when(purchaseService.getRecord(any())).thenReturn(
PurchaseRecordDO.builder()
.productId(1L)
.productName("产品")
.endTime(LocalDate.now())
.build()
);
when(productDelayRecordMapper.selectOne(any())).thenReturn(null);
// 准备参数
ProductDelayPageReqVO reqVO = new ProductDelayPageReqVO();
reqVO.setOrganName("晨丰科技");
reqVO.setProductName("ERP产品");
reqVO.setDelayDuration(3);
reqVO.setPageNo(1);
reqVO.setPageSize(10);
// 调用
PageResult<ProductDelayRespVO> pageResult = productDelayService.getPage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
ProductDelayRespVO respVO = pageResult.getList().get(0);
assertEquals("晨丰科技", respVO.getOrganName());
assertEquals("ERP产品", respVO.getProductName());
assertEquals(3, respVO.getDelayDuration());
assertServiceException(() -> productDelayService.createProductDelay(reqVO), PRODUCT_DELAY_UNIT_NOT_SUPPORT);
}
@Test
public void testGetRecordsByPurchaseId() {
// 准备数据
Long purchaseId = randomLongId();
Long organId = randomLongId();
void testGetRecordsByPurchaseId_success() {
Long purchaseId = 100L;
Long organId = 200L;
// mock 数据
ProductDelayRecordDO record1 = randomPojo(ProductDelayRecordDO.class, o -> {
o.setOrganName("晨丰科技");
o.setProductName("ERP产品");
o.setDelayDuration(3);
o.setDelayDurationUnit(DurationUnitEnum.MONTH.getCode());
o.setPurchaseId(purchaseId);
o.setOrganId(organId);
});
recordMapper.insert(record1);
ProductDelayRecordDO recordDO = new ProductDelayRecordDO();
recordDO.setDelayDuration(6);
recordDO.setDelayDurationUnit(2);
recordDO.setDelayTime(LocalDate.now());
// 不匹配的数据
recordMapper.insert(randomPojo(ProductDelayRecordDO.class, o -> {
o.setOrganName("其他组织");
o.setProductName("ERP产品");
o.setDelayDurationUnit(DurationUnitEnum.MONTH.getCode());
}));
when(productDelayRecordMapper.selectList(any()))
.thenReturn(List.of(recordDO));
// 调用
List<ProductDelayRespVO> records = productDelayService.getRecordsByPurchaseId(purchaseId, organId);
List<ProductDelayRespVO> result =
productDelayService.getRecordsByPurchaseId(purchaseId, organId);
// 断言
assertEquals(1, records.size());
// 验证按 ID 倒序
assertEquals(3, records.get(0).getDelayDuration());
assertEquals(1, result.size());
assertEquals(6, result.get(0).getDelayDuration());
assertEquals(2, result.get(0).getDelayDurationUnit());
verify(productDelayRecordMapper).selectList(any());
}
@Test
public void testGetActiveRecordsByProductId_withRecords() {
// 准备数据
Long productId = randomLongId();
Long organId = randomLongId();
Long purchaseId = randomLongId();
void testGetRecordsByPurchaseId_empty() {
when(productDelayRecordMapper.selectList(any()))
.thenReturn(Collections.emptyList());
// 插入活跃的购买记录
PurchaseRecordDO purchaseRecord = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(purchaseId);
o.setOrganId(organId);
o.setProductId(productId);
o.setStatus(PurchaseRecordStatusEnum.ACTIVE.getStatus());
o.setCurrency(null);
o.setIsInvocing(null);
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
});
purchaseRecordMapper.insert(purchaseRecord);
List<ProductDelayRespVO> result =
productDelayService.getRecordsByPurchaseId(1L, 1L);
// 插入延期记录
ProductDelayRecordDO delayRecord = randomPojo(ProductDelayRecordDO.class, o -> {
o.setOrganId(organId);
o.setProductId(productId);
o.setPurchaseId(purchaseId);
o.setDelayDuration(3);
o.setDelayDurationUnit(DurationUnitEnum.MONTH.getCode());
o.setDelayTime(LocalDate.now().plusMonths(3));
o.setEndTime(LocalDate.now());
});
recordMapper.insert(delayRecord);
// 调用
PreviouProductDelayRespVO result = productDelayService.getActiveRecordsByProductId(productId, organId);
// 断言
assertNotNull(result);
assertTrue(result.isEmpty());
}
@Test
void testGetPage_success() {
ProductDelayPageReqVO reqVO = new ProductDelayPageReqVO();
ProductDelayRecordDO recordDO = new ProductDelayRecordDO();
recordDO.setId(1L);
recordDO.setDelayDuration(3);
recordDO.setDelayDurationUnit(1);
PageResult<ProductDelayRecordDO> pageResult =
new PageResult<>(List.of(recordDO), 1L);
when(productDelayRecordMapper.selectPage(reqVO))
.thenReturn(pageResult);
PageResult<ProductDelayRespVO> result =
productDelayService.getPage(reqVO);
assertEquals(1L, result.getTotal());
assertEquals(1, result.getList().size());
assertEquals(3, result.getList().get(0).getDelayDuration());
verify(productDelayRecordMapper).selectPage(reqVO);
}
@Test
void testGetActiveRecordsByProductId_noActivePurchase() {
Long productId = 1L;
Long organId = 2L;
when(purchaseRecordMapper.selectOne(any()))
.thenReturn(null);
PreviouProductDelayRespVO result =
productDelayService.getActiveRecordsByProductId(productId, organId);
assertNotNull(result);
assertNull(result.getPreviouPurchaseRecord());
assertTrue(
result.getDelayRespVOList() == null
|| result.getDelayRespVOList().isEmpty()
);
verify(purchaseRecordMapper).selectOne(any());
verifyNoInteractions(productDelayRecordMapper);
}
@Test
void testGetActiveRecordsByProductId_success() {
Long productId = 1L;
Long organId = 2L;
PurchaseRecordDO purchase = new PurchaseRecordDO();
purchase.setId(10L);
purchase.setProductId(productId);
purchase.setOrganId(organId);
ProductDelayRecordDO delay = new ProductDelayRecordDO();
delay.setDelayDuration(3);
delay.setDelayDurationUnit(1);
delay.setDelayTime(LocalDate.now());
when(purchaseRecordMapper.selectOne(any()))
.thenReturn(purchase);
when(productDelayRecordMapper.selectList(any()))
.thenReturn(List.of(delay));
PreviouProductDelayRespVO result =
productDelayService.getActiveRecordsByProductId(productId, organId);
assertNotNull(result);
// 断言 purchase
assertNotNull(result.getPreviouPurchaseRecord());
assertEquals(purchaseId, result.getPreviouPurchaseRecord().getId());
assertEquals(10L, result.getPreviouPurchaseRecord().getId());
// 断言 delay 列表
assertNotNull(result.getDelayRespVOList());
assertEquals(1, result.getDelayRespVOList().size());
assertEquals(3, result.getDelayRespVOList().get(0).getDelayDuration());
verify(purchaseRecordMapper).selectOne(any());
verify(productDelayRecordMapper).selectList(any());
}
@Test
public void testGetActiveRecordsByProductId_noPurchaseRecord() {
// 准备数据
Long productId = randomLongId();
Long organId = randomLongId();
void updatePurchaseDelayRecordsPaidAndRemark_success() {
// given
Long organId = 1L;
Boolean paid = true;
// 调用(没有购买记录)
PreviouProductDelayRespVO result = productDelayService.getActiveRecordsByProductId(productId, organId);
ProductDelayRecordDO recordDO = new ProductDelayRecordDO();
recordDO.setId(100L);
recordDO.setRemark("test remark");
// 断言
assertNotNull(result);
assertNull(result.getPreviouPurchaseRecord());
assertNull(result.getDelayRespVOList());
List<ProductDelayRecordDO> list = Collections.singletonList(recordDO);
// mock update 行为
when(productDelayRecordMapper.update(any(LambdaUpdateWrapper.class)))
.thenReturn(1);
// when
productDelayService.updatePurchaseDelayRecordsPaidAndRemark(list, organId, paid);
// then
verify(productDelayRecordMapper, times(1))
.update(any(LambdaUpdateWrapper.class));
}
@Test
public void testUpdatePurchaseDelayRecordsPaidAndRemark() {
// 准备数据
Long organId = randomLongId();
void updatePurchaseDelayRecordsPaid_success() {
// given
Long purchaseId = 10L;
Long organId = 1L;
ProductDelayRecordDO record1 = randomPojo(ProductDelayRecordDO.class, o -> {
o.setPaid(false);
o.setRemark(null);
o.setDelayDuration(3);
o.setDelayDurationUnit(DurationUnitEnum.MONTH.getCode());
o.setOrganId(organId);
});
when(productDelayRecordMapper.update(any(LambdaUpdateWrapper.class)))
.thenReturn(2); // 模拟更新 2 条
recordMapper.insert(record1);
// 准备更新数据
record1.setRemark("备注1");
List<ProductDelayRecordDO> updateList = Arrays.asList(record1);
// 调用
productDelayService.updatePurchaseDelayRecordsPaidAndRemark(updateList, organId, true);
// 断言
ProductDelayRecordDO dbRecord1 = recordMapper.selectById(record1.getId());
assertTrue(dbRecord1.getPaid());
assertEquals("备注1", dbRecord1.getRemark());
}
@Test
public void testUpdatePurchaseDelayRecordsPaid() {
// 准备数据
Long purchaseId = randomLongId();
Long organId = randomLongId();
ProductDelayRecordDO record1 = randomPojo(ProductDelayRecordDO.class, o -> {
o.setDelayDurationUnit(DurationUnitEnum.MONTH.getCode());
o.setOrganId(organId);
o.setPurchaseId(purchaseId);
o.setPaid(false);
});
recordMapper.insert(record1);
// 调用
// when
productDelayService.updatePurchaseDelayRecordsPaid(purchaseId, organId);
// 断言
ProductDelayRecordDO dbRecord1 = recordMapper.selectById(record1.getId());
assertTrue(dbRecord1.getPaid());
// then
verify(productDelayRecordMapper, times(1))
.update(any(LambdaUpdateWrapper.class));
}
@Test
public void testResetPurchaseDelayRecordsRemark() {
// 准备数据
Long purchaseId = randomLongId();
Long organId = randomLongId();
void resetPurchaseDelayRecordsRemark_success() {
// given
Long purchaseId = 10L;
Long organId = 1L;
ProductDelayRecordDO record1 = randomPojo(ProductDelayRecordDO.class, o -> {
o.setRemark("测试备注");
o.setDelayDuration(3);
o.setDelayDurationUnit(DurationUnitEnum.MONTH.getCode());
o.setOrganId(organId);
o.setPurchaseId(purchaseId);
});
recordMapper.insert(record1);
when(productDelayRecordMapper.update(any(LambdaUpdateWrapper.class)))
.thenReturn(1);
// 调用
// when
productDelayService.resetPurchaseDelayRecordsRemark(purchaseId, organId);
// 断言
ProductDelayRecordDO dbRecord1 = recordMapper.selectById(record1.getId());
assertNull(dbRecord1.getRemark());
// then
verify(productDelayRecordMapper, times(1))
.update(any(LambdaUpdateWrapper.class));
}
}
@@ -1,64 +1,50 @@
package com.cf.imes.module.system.service.funds.incomeandexpense;
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.incomeandexpense.IncomeExpenseDetailsDO;
import com.cf.imes.module.system.dal.mysql.incomeandexpense.IncomeExpenseDetailsMapper;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import java.math.BigDecimal;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* {@link IncomeExpenseServiceImpl} 的单元测试类
*
* @author Gqr
*/
@Import(IncomeExpenseServiceImpl.class)
class IncomeExpenseServiceImplTest extends BaseDbAndRedisUnitTest {
class IncomeExpenseServiceImplTest extends BaseMockitoUnitTest {
@Resource
@InjectMocks
private IncomeExpenseServiceImpl incomeExpenseService;
@Resource
@Mock
private IncomeExpenseDetailsMapper incomeExpenseDetailsMapper;
@Test
void testCreateDetail() {
// 准备数据
IncomeExpenseDetailsDO incomeExpenseDetailsDO = new IncomeExpenseDetailsDO();
incomeExpenseDetailsDO.setBusinessNo("BUS20251215001");
incomeExpenseDetailsDO.setOrderNo("ORD20251215001");
incomeExpenseDetailsDO.setOrganId(1L);
incomeExpenseDetailsDO.setPurchaseId(100L);
incomeExpenseDetailsDO.setTradeType(1);
incomeExpenseDetailsDO.setIncomeExpenseType(2);
incomeExpenseDetailsDO.setAmount(new BigDecimal("100.00"));
incomeExpenseDetailsDO.setCurrency(1);
incomeExpenseDetailsDO.setCurrencyUnit("CNY");
incomeExpenseDetailsDO.setRemark("测试收支明细");
void createDetail_success() {
// given
IncomeExpenseDetailsDO detailDO = new IncomeExpenseDetailsDO();
// 调用方法
Long id = incomeExpenseService.createDetail(incomeExpenseDetailsDO);
doAnswer(invocation -> {
IncomeExpenseDetailsDO arg = invocation.getArgument(0);
arg.setId(100L); // 手动回填 ID
return 1;
}).when(incomeExpenseDetailsMapper).insert(any(IncomeExpenseDetailsDO.class));
// 验证结果
// when
Long id = incomeExpenseService.createDetail(detailDO);
// then
assertNotNull(id);
assertTrue(id > 0);
assertEquals(100L, id);
// 验证数据库中是否已插入数据
IncomeExpenseDetailsDO dbRecord = incomeExpenseDetailsMapper.selectById(id);
assertNotNull(dbRecord);
assertEquals("BUS20251215001", dbRecord.getBusinessNo());
assertEquals("ORD20251215001", dbRecord.getOrderNo());
assertEquals(1L, dbRecord.getOrganId());
assertEquals(100L, dbRecord.getPurchaseId());
assertEquals(1, dbRecord.getTradeType());
assertEquals(2, dbRecord.getIncomeExpenseType());
assertEquals(new BigDecimal("100.00"), dbRecord.getAmount());
assertEquals(1, dbRecord.getCurrency());
assertEquals("CNY", dbRecord.getCurrencyUnit());
assertEquals("测试收支明细", dbRecord.getRemark());
verify(incomeExpenseDetailsMapper, times(1))
.insert(any(IncomeExpenseDetailsDO.class));
}
}
@@ -1,14 +1,18 @@
package com.cf.imes.module.system.service.funds.invoice;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cf.imes.framework.common.exception.ServiceException;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.security.core.LoginUser;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.framework.security.test.WithMockLoginUser;
import com.cf.imes.framework.test.core.ut.BaseDbAndRedisUnitTest;
import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest;
import com.cf.imes.module.infra.api.file.FileApi;
import com.cf.imes.module.system.common.WithMockLoginUserExtension;
import com.cf.imes.module.system.controller.admin.funds.invoice.vo.*;
import com.cf.imes.module.system.dal.dataobject.funds.invoice.InvoiceRecordsDO;
import com.cf.imes.module.system.dal.dataobject.funds.invoice.InvoiceTitleInfoDO;
@@ -22,13 +26,15 @@ import com.cf.imes.module.system.enums.pay.InvoiceStatusEnum;
import com.cf.imes.module.system.enums.pay.PayChannelCodeEnum;
import com.cf.imes.module.system.enums.pay.TradeTypeEnum;
import com.cf.imes.module.system.service.organ.OrganService;
import jakarta.annotation.Resource;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
@@ -39,7 +45,13 @@ import static com.cf.imes.framework.test.core.util.RandomUtils.randomPojo;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@@ -48,31 +60,35 @@ import static org.mockito.Mockito.when;
* @author Gqr
* @since 2025/12/15 15:31
*/
@Import(InvoiceServiceImpl.class)
class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
@ExtendWith(WithMockLoginUserExtension.class)
class InvoiceServiceImplTest extends BaseMockitoUnitTest {
@Resource
@InjectMocks
private InvoiceServiceImpl invoiceService;
@Resource
@Mock
private InvoiceTitleInfoMapper invoiceTitleInfoMapper;
@Resource
@Mock
private PurchaseRecordMapper purchaseRecordMapper;
@Resource
@Mock
private InvoiceRecordsMapper invoiceRecordsMapper;
@MockitoBean
@Mock
private OrganService organService;
@MockitoBean
@Mock
private FileApi fileApi;
@BeforeAll
static void init(){
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), PurchaseRecordDO.class);
}
@Test
@WithMockLoginUser
void testGetInvoiceTitle() {
// 准备参数
Long organId = SecurityFrameworkUtils.getUserOrganId();
// 使用真实数据查询发票抬头信息
@@ -81,8 +97,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setOrganId(organId);
o.setInvoiceTitle("测试公司");
});
invoiceTitleInfoMapper.insert(invoiceTitleInfoDO);
when(invoiceTitleInfoMapper.selectOne(any(LambdaQueryWrapper.class))).thenReturn(invoiceTitleInfoDO);
// 调用
InvoiceTitleInfo result = invoiceService.getInvoiceTitle();
@@ -92,6 +107,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
assertEquals(1L, result.getId());
assertEquals("测试公司", result.getInvoiceTitle());
assertEquals(organId, result.getOrganId());
}
@Test
@@ -106,17 +122,32 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
reqVO.setTaxNumber("91330101MA2HXXXXXX");
reqVO.setEmail("test@company.com");
// 内部校验
when(invoiceTitleInfoMapper.selectOne(any(LambdaQueryWrapper.class))).thenReturn(null);
invoiceService.insetInvoiceTitle(reqVO);
// ====== 校验数据库 ======
InvoiceTitleInfoDO dbRecord = invoiceTitleInfoMapper.selectOne(
new LambdaQueryWrapper<InvoiceTitleInfoDO>()
.eq(InvoiceTitleInfoDO::getOrganId, organId)
);
// 不走更新
verify(invoiceTitleInfoMapper, never()).updateById(any(InvoiceTitleInfoDO.class));
assertNotNull(dbRecord);
assertEquals("测试公司", dbRecord.getInvoiceTitle());
assertEquals("91330101MA2HXXXXXX", dbRecord.getTaxNumber());
// 校验新增
ArgumentCaptor<InvoiceTitleInfoDO> captor =
ArgumentCaptor.forClass(InvoiceTitleInfoDO.class);
verify(invoiceTitleInfoMapper).insert(captor.capture());
InvoiceTitleInfoDO inserted = captor.getValue();
assertEquals(organId, inserted.getOrganId());
assertEquals(reqVO.getInvoiceTitle(), inserted.getInvoiceTitle());
assertEquals(reqVO.getInvoiceType(), inserted.getInvoiceType());
assertEquals(reqVO.getIssueType(), inserted.getIssueType());
assertEquals(reqVO.getTaxNumber(), inserted.getTaxNumber());
assertEquals(reqVO.getBankName(), inserted.getBankName());
assertEquals(reqVO.getBankAccount(), inserted.getBankAccount());
assertEquals(reqVO.getRegisteredAddress(), inserted.getRegisteredAddress());
assertEquals(reqVO.getFixedPhone(), inserted.getFixedPhone());
assertEquals(reqVO.getEmail(), inserted.getEmail());
}
@Test
@@ -128,15 +159,11 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
reqVO.setInvoiceType(0);
reqVO.setTaxNumber(null);
ServiceException ex = assertThrows(
ServiceException.class,
() -> invoiceService.insetInvoiceTitle(reqVO)
);
assertServiceException(() -> invoiceService.insetInvoiceTitle(reqVO), INVOICE_TITLE_ENTERPRISE_TAXNUMBER_EMPTY_ERROR);
// 校验未调用
verify(invoiceTitleInfoMapper, never()).selectOne(any(LambdaQueryWrapper.class));
assertEquals(
INVOICE_TITLE_ENTERPRISE_TAXNUMBER_EMPTY_ERROR.getCode(),
ex.getCode()
);
}
@Test
@@ -144,7 +171,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
void insetInvoiceTitle_sameOrgan_throwOrgExists() {
Long organId = SecurityFrameworkUtils.getUserOrganId();
invoiceTitleInfoMapper.insert(InvoiceTitleInfoDO.builder()
when(invoiceTitleInfoMapper.selectOne(any())).thenReturn(InvoiceTitleInfoDO.builder()
.organId(organId)
.issueType(InvoiceIssueTypeEnum.PERSONAL.getValue())
.invoiceTitle("已存在")
@@ -154,15 +181,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
reqVO.setInvoiceTitle("新抬头");
reqVO.setIssueType(InvoiceIssueTypeEnum.PERSONAL.getValue());
ServiceException ex = assertThrows(
ServiceException.class,
() -> invoiceService.insetInvoiceTitle(reqVO)
);
assertEquals(
INVOICE_TITLE_ORG_EXISTS_ERROR.getCode(),
ex.getCode()
);
assertServiceException(() -> invoiceService.insetInvoiceTitle(reqVO), INVOICE_TITLE_ORG_EXISTS_ERROR);
}
@Test
@@ -173,41 +192,26 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
reqVO.setInvoiceTitle("测试抬头");
reqVO.setIssueType(InvoiceIssueTypeEnum.PERSONAL.getValue());
ServiceException ex = assertThrows(
ServiceException.class,
() -> invoiceService.insetInvoiceTitle(reqVO)
);
assertEquals(
INVOICE_TITLE_NOT_EXISTS_ERROR.getCode(),
ex.getCode()
);
assertServiceException(() -> invoiceService.insetInvoiceTitle(reqVO), INVOICE_TITLE_NOT_EXISTS_ERROR);
}
@Test
@WithMockLoginUser
void insetInvoiceTitle_update_orgNotMatch_throwException() {
InvoiceTitleInfoDO exist = InvoiceTitleInfoDO.builder()
.id(100L)
.organId(2L)
.issueType(InvoiceIssueTypeEnum.PERSONAL.getValue())
.invoiceTitle("原抬头")
.build();
invoiceTitleInfoMapper.insert(exist);
when(invoiceTitleInfoMapper.selectById(any())).thenReturn(exist);
InvoiceTitleSaveReqVO reqVO = new InvoiceTitleSaveReqVO();
reqVO.setId(exist.getId());
reqVO.setInvoiceTitle("非法更新");
reqVO.setIssueType(exist.getIssueType());
ServiceException ex = assertThrows(
ServiceException.class,
() -> invoiceService.insetInvoiceTitle(reqVO)
);
assertEquals(
INVOICE_TITLE_NOT_EXISTS_ERROR.getCode(),
ex.getCode()
);
assertServiceException(() -> invoiceService.insetInvoiceTitle(reqVO), INVOICE_TITLE_NOT_EXISTS_ERROR);
}
@Test
@@ -223,26 +227,26 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
invoiceService.insetInvoiceTitle(reqVO);
// 验证数据库
List<InvoiceTitleInfoDO> list = invoiceTitleInfoMapper.selectList(null);
assertEquals(1, list.size());
InvoiceTitleInfoDO saved = list.get(0);
assertEquals(organId, saved.getOrganId());
assertEquals("新增抬头", saved.getInvoiceTitle());
// 验证插入
verify(invoiceTitleInfoMapper).insert(argThat((InvoiceTitleInfoDO infoDO) ->
infoDO.getInvoiceTitle().equals(reqVO.getInvoiceTitle())
&& infoDO.getOrganId().equals(organId)
&& infoDO.getIssueType().equals(reqVO.getIssueType())
&& infoDO.getInvoiceType().equals(reqVO.getInvoiceType())
&& infoDO.getEmail().equals(reqVO.getEmail())
));
}
@Test
@WithMockLoginUser
void insetInvoiceTitle_enterprise_taxNumberExists_throwException() {
// 先插入一条企业发票抬头
InvoiceTitleInfoDO exist = InvoiceTitleInfoDO.builder()
when(invoiceTitleInfoMapper.selectOne(any())).thenReturn(null).thenReturn(InvoiceTitleInfoDO.builder()
.organId(2L) // 不同组织也没关系
.invoiceTitle("已存在抬头")
.issueType(InvoiceIssueTypeEnum.ENTERPRISE.getValue())
.taxNumber("91330100XXXXXX")
.build();
invoiceTitleInfoMapper.insert(exist);
.build());
// 再新增一条相同税号
InvoiceTitleSaveReqVO reqVO = new InvoiceTitleSaveReqVO();
@@ -250,15 +254,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
reqVO.setIssueType(InvoiceIssueTypeEnum.ENTERPRISE.getValue());
reqVO.setTaxNumber("91330100XXXXXX");
ServiceException ex = assertThrows(
ServiceException.class,
() -> invoiceService.insetInvoiceTitle(reqVO)
);
assertEquals(
INVOICE_TITLE_TAXPAYERID_EXISTS_ERROR.getCode(),
ex.getCode()
);
assertServiceException(() -> invoiceService.insetInvoiceTitle(reqVO), INVOICE_TITLE_TAXPAYERID_EXISTS_ERROR);
}
@Test
@@ -266,13 +262,13 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
void insetInvoiceTitle_update_success() {
Long organId = SecurityFrameworkUtils.getUserOrganId();
// given:数据库已有数据(organId 一定要一致)
InvoiceTitleInfoDO exist = InvoiceTitleInfoDO.builder()
.id(100L)
.organId(organId)
.invoiceTitle("旧抬头")
.issueType(InvoiceIssueTypeEnum.PERSONAL.getValue())
.build();
invoiceTitleInfoMapper.insert(exist);
when(invoiceTitleInfoMapper.selectById(exist.getId())).thenReturn(exist);
// when:更新
InvoiceTitleSaveReqVO reqVO = new InvoiceTitleSaveReqVO();
@@ -282,17 +278,26 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
invoiceService.insetInvoiceTitle(reqVO);
// then:断言更新成功
InvoiceTitleInfoDO updated = invoiceTitleInfoMapper.selectById(exist.getId());
assertEquals("新抬头", updated.getInvoiceTitle());
// 捕获 update 的参数,断言字段
ArgumentCaptor<InvoiceTitleInfoDO> captor =
ArgumentCaptor.forClass(InvoiceTitleInfoDO.class);
verify(invoiceTitleInfoMapper).updateById(captor.capture());
InvoiceTitleInfoDO actual = captor.getValue();
assertEquals(reqVO.getId(), actual.getId());
assertEquals(reqVO.getInvoiceTitle(), actual.getInvoiceTitle());
assertEquals(reqVO.getIssueType(), actual.getIssueType());
}
@Test
@WithMockLoginUser
void getAvailablePage_whenEmptyList_returnEmptyPageResult() {
// given
InvoiceAmountAndAvailablePageReqVO reqVO = new InvoiceAmountAndAvailablePageReqVO();
when(purchaseRecordMapper.selectPage(any(InvoiceAmountAndAvailablePageReqVO.class))).thenReturn(new PageResult());
// when
PageResult<InvoiceAvailablePageRespVO> result =
invoiceService.getAvailablePage(reqVO);
@@ -304,7 +309,6 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
}
@Test
@WithMockLoginUser(organId = 1L)
void getAvailablePage_whenHasData_returnConvertedPage() {
// given
InvoiceAmountAndAvailablePageReqVO reqVO =
@@ -321,7 +325,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setInitial(false);
o.setOrganId(1L);
});
purchaseRecordMapper.insert(invoiceRecordsDO);
when(purchaseRecordMapper.selectPage(any(InvoiceAmountAndAvailablePageReqVO.class))).thenReturn(new PageResult(List.of(invoiceRecordsDO), 1L));
// when
PageResult<InvoiceAvailablePageRespVO> result =
@@ -364,7 +368,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
.issueType(InvoiceIssueTypeEnum.ENTERPRISE.getValue())
.taxNumber("91330100XXXXXX")
.build();
invoiceTitleInfoMapper.insert(exist);
when(invoiceTitleInfoMapper.selectOne(any())).thenReturn(exist);
InvoiceRecordsReqVO reqVO = new InvoiceRecordsReqVO();
@@ -379,24 +383,28 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setInitial(false);
o.setOrganId(1L);
});
purchaseRecordMapper.insert(invoiceRecordsDO);
when(purchaseRecordMapper.selectByIds(anyList())).thenReturn(List.of(invoiceRecordsDO));
// 有不可开票状态的记录
reqVO.setPurchaseRecordId(List.of(invoiceRecordsDO.getId()));
assertServiceException(() -> invoiceService.applyInvoice(reqVO), INVOICE_APPLY_UNINVOICEABLE_EXIST);
// 可开金额为0
invoiceRecordsDO.setId(null);
invoiceRecordsDO.setExternalSpent(BigDecimal.ZERO);
invoiceRecordsDO.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
purchaseRecordMapper.insert(invoiceRecordsDO);
when(purchaseRecordMapper.selectByIds(anyList())).thenReturn(List.of(invoiceRecordsDO));
reqVO.setPurchaseRecordId(List.of(invoiceRecordsDO.getId()));
when(purchaseRecordMapper.getInvoicableAmount(anyLong(), anyList())).thenReturn(BigDecimal.ZERO);
assertServiceException(() -> invoiceService.applyInvoice(reqVO), INVOICE_AMOUNT_ZERO_ERROR);
// 更新开票状态和开票id数量不匹配
invoiceRecordsDO.setId(null);
invoiceRecordsDO.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
invoiceRecordsDO.setExternalSpent(new BigDecimal("100"));
purchaseRecordMapper.insert(invoiceRecordsDO);
when(purchaseRecordMapper.selectByIds(anyList())).thenReturn(List.of(invoiceRecordsDO));
when(purchaseRecordMapper.getInvoicableAmount(anyLong(), anyList())).thenReturn(BigDecimal.ONE);
when(purchaseRecordMapper.update(any(LambdaUpdateWrapper.class))).thenReturn(10);
reqVO.setPurchaseRecordId(List.of(invoiceRecordsDO.getId(), 999L));
assertServiceException(
@@ -409,14 +417,18 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
@Test
@WithMockLoginUser(organId = 1L)
void applyInvoice_success() {
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
Long organId = loginUser.getOrganId();
Long userId = loginUser.getId();
// 先插入一条企业发票抬头
InvoiceTitleInfoDO exist = InvoiceTitleInfoDO.builder()
.organId(1L) // 不同组织也没关系
.organId(organId) // 不同组织也没关系
.invoiceTitle("已存在抬头")
.issueType(InvoiceIssueTypeEnum.ENTERPRISE.getValue())
.taxNumber("91330100XXXXXX")
.build();
invoiceTitleInfoMapper.insert(exist);
when(invoiceTitleInfoMapper.selectOne(any())).thenReturn(exist);
InvoiceRecordsReqVO reqVO = new InvoiceRecordsReqVO();
@@ -428,9 +440,11 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
o.setOrganId(1L);
o.setOrganId(organId);
});
purchaseRecordMapper.insert(invoiceRecordsDO);
when(purchaseRecordMapper.selectByIds(anyList())).thenReturn(List.of(invoiceRecordsDO));
when(purchaseRecordMapper.getInvoicableAmount(anyLong(), anyList())).thenReturn(BigDecimal.ONE);
when(purchaseRecordMapper.update(any(LambdaUpdateWrapper.class))).thenReturn(1);
Long recordId = invoiceRecordsDO.getId();
reqVO.setPurchaseRecordId(List.of(recordId));
@@ -438,28 +452,30 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
// 组织
OrganizationDO org = new OrganizationDO();
org.setName("测试组织");
org.setId(1L);
org.setId(organId);
when(organService.validOrgan(1L)).thenReturn(org);
assertDoesNotThrow(() -> {
invoiceService.applyInvoice(reqVO);
});
List<InvoiceRecordsDO> invoiceRecordsDOS = invoiceRecordsMapper.selectList();
assertEquals(1, invoiceRecordsDOS.size());
InvoiceRecordsDO query = invoiceRecordsDOS.get(0);
assertNotNull(invoiceRecordsDO);
assertEquals(invoiceRecordsDO.getOrganId(), invoiceRecordsDO.getOrganId());
assertEquals(query.getPurchaseIds(), List.of(invoiceRecordsDO.getId()).toString());
assertEquals("测试组织", query.getOrganName());
// 验证插入
verify(invoiceRecordsMapper).insert(argThat((InvoiceRecordsDO recordsDO) ->
recordsDO.getOrganId().equals(organId)
&& recordsDO.getUserId().equals(userId)
&& recordsDO.getOrganName().equals("测试组织")
&& recordsDO.getInvoiceAmount().equals(BigDecimal.ONE)
&& recordsDO.getStatus().equals(InvoiceStatusEnum.PENDINGINVOICING.getCode())
));
}
@Test
@WithMockLoginUser
void getInvoiceRecords_whenEmptyList_returnEmptyPageResult() {
// given
InvoiceDetailsPageReqVO pageReqVO = new InvoiceDetailsPageReqVO();
// when
when(invoiceRecordsMapper.selectInvoiceRecordsPage(any())).thenReturn(new PageResult<>());
PageResult<InvoiceRecordsRespVO> result = invoiceService.getInvoiceRecords(pageReqVO);
// then
@@ -469,7 +485,6 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
}
@Test
@WithMockLoginUser
void getInvoiceRecords_whenHasData_returnConvertedPage() {
// given
InvoiceDetailsPageReqVO pageReqVO = new InvoiceDetailsPageReqVO();
@@ -479,7 +494,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setInvoiceAmount(new BigDecimal("100.00"));
o.setStatus(InvoiceStatusEnum.INVOICABLE.getCode());
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
when(invoiceRecordsMapper.selectInvoiceRecordsPage(any())).thenReturn(new PageResult<>(List.of(invoiceRecordsDO), 1L));
// when
PageResult<InvoiceRecordsRespVO> result = invoiceService.getInvoiceRecords(pageReqVO);
@@ -496,13 +511,11 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
}
@Test
@WithMockLoginUser
void getInvoiceRecordDetail_whenRecordNotExists_thenThrowException() {
assertServiceException(() -> invoiceService.getInvoiceRecordDetail(1L), INVOICE_NO_EXIST);
}
@Test
@WithMockLoginUser
void getInvoiceRecordDetail_whenRecordExists_thenReturnDetail() {
// 准备数据
InvoiceRecordsDO invoiceRecordsDO = randomPojo(InvoiceRecordsDO.class, o -> {
@@ -512,7 +525,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setPurchaseIds("[1, 2]");
o.setInvoiceTitleInfo(zipString("{\"invoiceTitle\":\"测试公司\"}"));
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
when(invoiceRecordsMapper.selectById(anyLong())).thenReturn(invoiceRecordsDO);
PurchaseRecordDO purchase1 = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(1L);
@@ -523,7 +536,6 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
});
purchaseRecordMapper.insert(purchase1);
PurchaseRecordDO purchase2 = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(2L);
@@ -534,7 +546,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
});
purchaseRecordMapper.insert(purchase2);
when(purchaseRecordMapper.selectList(any(LambdaQueryWrapper.class))).thenReturn(List.of(purchase1, purchase2));
// 调用方法
InvoiceDetailsRespVO result = invoiceService.getInvoiceRecordDetail(1L);
@@ -567,7 +579,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setId(1L);
o.setStatus(InvoiceStatusEnum.INVOICINGSUCCESSFUL.getCode());
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
when(invoiceRecordsMapper.selectById(1L)).thenReturn(invoiceRecordsDO);
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
@@ -583,7 +595,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setId(1L);
o.setStatus(InvoiceStatusEnum.INVOICINGFAILED.getCode());
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
when(invoiceRecordsMapper.selectById(1L)).thenReturn(invoiceRecordsDO);
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
@@ -602,7 +614,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setInvoiceTitleId(1L);
o.setOrganId(1L);
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
when(invoiceRecordsMapper.selectById(1L)).thenReturn(invoiceRecordsDO);
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
@@ -621,14 +633,14 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setInvoiceTitleId(1L);
o.setOrganId(1L);
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
when(invoiceRecordsMapper.selectById(1L)).thenReturn(invoiceRecordsDO);
InvoiceTitleInfoDO title = randomPojo(InvoiceTitleInfoDO.class, o -> {
o.setId(1L);
o.setOrganId(1L);
o.setInvoiceTitle("测试公司");
});
invoiceTitleInfoMapper.insert(title);
when(invoiceTitleInfoMapper.selectById(anyLong())).thenReturn(title);
PurchaseRecordDO purchase = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(1L);
@@ -637,7 +649,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
});
purchaseRecordMapper.insert(purchase);
when(purchaseRecordMapper.selectByIds(anyList())).thenReturn(List.of(purchase));
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
@@ -657,14 +669,14 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setInvoiceTitleId(1L);
o.setOrganId(1L);
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
when(invoiceRecordsMapper.selectById(1L)).thenReturn(invoiceRecordsDO);
InvoiceTitleInfoDO title = randomPojo(InvoiceTitleInfoDO.class, o -> {
o.setId(1L);
o.setOrganId(1L);
o.setInvoiceTitle("测试公司");
});
invoiceTitleInfoMapper.insert(title);
when(invoiceTitleInfoMapper.selectById(anyLong())).thenReturn(title);
PurchaseRecordDO purchase = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(1L);
@@ -673,7 +685,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
});
purchaseRecordMapper.insert(purchase);
when(purchaseRecordMapper.selectByIds(anyList())).thenReturn(List.of(purchase));
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
@@ -695,14 +707,14 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setOrganId(1L);
o.setInvoiceAmount(new BigDecimal("100.00"));
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
when(invoiceRecordsMapper.selectById(1L)).thenReturn(invoiceRecordsDO);
InvoiceTitleInfoDO title = randomPojo(InvoiceTitleInfoDO.class, o -> {
o.setId(1L);
o.setOrganId(1L);
o.setInvoiceTitle("测试公司");
});
invoiceTitleInfoMapper.insert(title);
when(invoiceTitleInfoMapper.selectById(anyLong())).thenReturn(title);
PurchaseRecordDO purchase = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(1L);
@@ -711,11 +723,12 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
});
purchaseRecordMapper.insert(purchase);
when(purchaseRecordMapper.selectByIds(anyList())).thenReturn(List.of(purchase));
// Mock 文件上传
Long fileId = 999L;
MockMultipartFile file = new MockMultipartFile("file", "测试公司-20231010101010-100.pdf", "application/pdf", "content".getBytes());
when(fileApi.createFileAndReturnId(any(byte[].class), anyString())).thenReturn(1L);
when(fileApi.createFileAndReturnId(any(byte[].class), anyString())).thenReturn(fileId);
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
@@ -727,17 +740,15 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
assertDoesNotThrow(() -> invoiceService.confirmInvoice(reqVO, file));
// 验证数据库更新
InvoiceRecordsDO updatedRecord = invoiceRecordsMapper.selectById(1L);
assertEquals(InvoiceStatusEnum.INVOICINGSUCCESSFUL.getCode(), updatedRecord.getStatus());
assertEquals("FP20231010101010", updatedRecord.getInvoiceNo());
assertEquals("同意开票", updatedRecord.getRemark());
assertEquals("测试用户", updatedRecord.getInvoicePerson());
assertEquals(1L, updatedRecord.getInvoicePersonId());
assertNotNull(updatedRecord.getInvoiceTime());
assertEquals(1L, updatedRecord.getInvoiceAttachmentId());
verify(invoiceRecordsMapper).updateById(argThat((InvoiceRecordsDO recordsDO) ->
recordsDO.getStatus().equals(InvoiceStatusEnum.INVOICINGSUCCESSFUL.getCode())
&& recordsDO.getRemark().equals(reqVO.getRemark())
&& recordsDO.getInvoiceAttachmentId().equals(fileId)
&& recordsDO.getInvoiceNo().equals(reqVO.getInvoiceNo())
));
PurchaseRecordDO updatedPurchase = purchaseRecordMapper.selectById(1L);
assertEquals(InvoiceStatusEnum.INVOICINGSUCCESSFUL.getCode(), updatedPurchase.getIsInvocing());
verify(purchaseRecordMapper, times(1))
.updateBatch(anyList());
}
@Test
@@ -751,14 +762,14 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setInvoiceTitleId(1L);
o.setOrganId(1L);
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
when(invoiceRecordsMapper.selectById(1L)).thenReturn(invoiceRecordsDO);
InvoiceTitleInfoDO title = randomPojo(InvoiceTitleInfoDO.class, o -> {
o.setId(1L);
o.setOrganId(1L);
o.setInvoiceTitle("测试公司");
});
invoiceTitleInfoMapper.insert(title);
when(invoiceTitleInfoMapper.selectById(anyLong())).thenReturn(title);
PurchaseRecordDO purchase = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(1L);
@@ -767,7 +778,7 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
});
purchaseRecordMapper.insert(purchase);
when(purchaseRecordMapper.selectByIds(anyList())).thenReturn(List.of(purchase));
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
@@ -778,96 +789,49 @@ class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
assertDoesNotThrow(() -> invoiceService.confirmInvoice(reqVO, null));
// 验证数据库更新
InvoiceRecordsDO updatedRecord = invoiceRecordsMapper.selectById(1L);
assertEquals(InvoiceStatusEnum.INVOICINGFAILED.getCode(), updatedRecord.getStatus());
assertEquals("拒绝开票", updatedRecord.getRemark());
assertEquals("测试用户", updatedRecord.getInvoicePerson());
assertEquals(1L, updatedRecord.getInvoicePersonId());
assertNotNull(updatedRecord.getInvoiceTime());
verify(invoiceRecordsMapper).updateById(argThat((InvoiceRecordsDO recordsDO) ->
recordsDO.getStatus().equals(InvoiceStatusEnum.INVOICINGFAILED.getCode())
&& recordsDO.getRemark().equals(reqVO.getRemark())
));
PurchaseRecordDO updatedPurchase = purchaseRecordMapper.selectById(1L);
assertEquals(InvoiceStatusEnum.INVOICABLE.getCode(), updatedPurchase.getIsInvocing());
verify(purchaseRecordMapper, times(1))
.updateBatch(anyList());
}
@Test
@WithMockLoginUser
void getInvoiceAmount_whenNoData_thenReturnZeroValues() {
InvoiceAmountRespVO invoiceAmountRespVO = new InvoiceAmountRespVO();
invoiceAmountRespVO.setInvocable(BigDecimal.ZERO);
invoiceAmountRespVO.setInTheInvoice(BigDecimal.ONE);
invoiceAmountRespVO.setInvoiced(BigDecimal.TEN);
when(purchaseRecordMapper.getOrgInvoiceAmountStatistics(anyLong())).thenReturn(invoiceAmountRespVO);
// 调用方法
InvoiceAmountRespVO result = invoiceService.getInvoiceAmount();
// 验证结果
assertNotNull(result);
assertEquals(BigDecimal.ZERO, result.getInvocable());
assertEquals(BigDecimal.ZERO, result.getInTheInvoice());
assertEquals(BigDecimal.ZERO, result.getInvoiced());
assertEquals(BigDecimal.ONE, result.getInTheInvoice());
assertEquals(BigDecimal.TEN, result.getInvoiced());
}
@Test
@WithMockLoginUser
void getInvoiceAmount_whenHasData_thenReturnCorrectValues() {
// 可开票
PurchaseRecordDO purchaseRecordDO = randomPojo(PurchaseRecordDO.class, o->{
o.setExternalSpent(new BigDecimal("100.00"));
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
o.setOrganId(SecurityFrameworkUtils.getUserOrganId());
});
purchaseRecordMapper.insert(purchaseRecordDO);
InvoiceAmountRespVO result = invoiceService.getInvoiceAmount();
assertNotNull(result);
assertEquals(new BigDecimal("100.00"), result.getInvocable());
// 开票中
purchaseRecordDO.setId(null);
purchaseRecordDO.setIsInvocing(InvoiceStatusEnum.PENDINGINVOICING.getCode());
purchaseRecordMapper.insert(purchaseRecordDO);
result = invoiceService.getInvoiceAmount();
assertNotNull(result);
assertEquals(new BigDecimal("100.00"), result.getInTheInvoice());
// 已开票
purchaseRecordDO.setId(null);
purchaseRecordDO.setIsInvocing(InvoiceStatusEnum.INVOICINGSUCCESSFUL.getCode());
purchaseRecordMapper.insert(purchaseRecordDO);
result = invoiceService.getInvoiceAmount();
assertNotNull(result);
assertEquals(new BigDecimal("100.00"), result.getInvoiced());
}
@Test
void getManageInvoiceAmount_whenNoData_thenReturnZeroValues() {
InvoiceAmountRespVO invoiceAmountRespVO = new InvoiceAmountRespVO();
invoiceAmountRespVO.setPendingInvoice(BigDecimal.TEN);
invoiceAmountRespVO.setInvoiced(BigDecimal.ZERO);
when(invoiceRecordsMapper.getManageInvoiceAmountStatistics()).thenReturn(invoiceAmountRespVO);
// 调用方法
InvoiceAmountRespVO result = invoiceService.getManageInvoiceAmount();
// 验证结果
assertNotNull(result);
assertEquals(BigDecimal.ZERO, result.getPendingInvoice());
assertEquals(BigDecimal.TEN, result.getPendingInvoice());
assertEquals(BigDecimal.ZERO, result.getInvoiced());
}
@Test
void getManageInvoiceAmount_whenHasData_thenReturnCorrectValues() {
// 待开票
InvoiceRecordsDO invoiceRecordsDO = randomPojo(InvoiceRecordsDO.class, o -> {
o.setInvoiceAmount(new BigDecimal("150.00"));
o.setStatus(InvoiceStatusEnum.PENDINGINVOICING.getCode());
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
InvoiceAmountRespVO result = invoiceService.getManageInvoiceAmount();
assertNotNull(result);
assertEquals(new BigDecimal("150.00"), result.getPendingInvoice());
// 已开票
invoiceRecordsDO.setId(null);
invoiceRecordsDO.setStatus(InvoiceStatusEnum.INVOICINGSUCCESSFUL.getCode());
invoiceRecordsDO.setInvoiceAmount(new BigDecimal("300.00"));
invoiceRecordsMapper.insert(invoiceRecordsDO);
result = invoiceService.getManageInvoiceAmount();
assertEquals(new BigDecimal("300.00"), result.getInvoiced());
}
@Test
void getFileExtension_whenFileNameIsNull_thenReturnEmpty() {
assertEquals("", InvoiceServiceImpl.getFileExtension(null));
@@ -3,31 +3,31 @@ package com.cf.imes.module.system.service.funds.organamount;
import com.cf.imes.framework.common.enums.StatisticsUnit;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.framework.security.test.WithMockLoginUser;
import com.cf.imes.framework.test.core.ut.BaseDbAndRedisUnitTest;
import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest;
import com.cf.imes.module.system.common.WithMockLoginUserExtension;
import com.cf.imes.module.system.controller.admin.funds.invoice.vo.InvoiceAmountRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.ManageAmountOverviewRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganAmountGroupByCreateTimeRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganFundsStatisticsReqVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganProductOverviewRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.TotalSalesAmountRespVO;
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.OrgEarliestPurchaseProductRespVO;
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
import com.cf.imes.module.system.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO;
import com.cf.imes.module.system.dal.mysql.incomeandexpense.IncomeExpenseDetailsMapper;
import com.cf.imes.module.system.service.funds.invoice.InvoiceService;
import com.cf.imes.module.system.service.funds.purchase.PurchaseService;
import com.cf.imes.module.system.service.organ.OrganService;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static com.cf.imes.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -35,27 +35,21 @@ import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
*
*
* @author Gqr
* @since 2025/12/31 14:00
*/
@Import(OrganAmountServiceImpl.class)
public class OrganAmountServiceImplTest extends BaseDbAndRedisUnitTest {
@Resource
@ExtendWith(WithMockLoginUserExtension.class)
class OrganAmountServiceImplTest extends BaseMockitoUnitTest {
@Mock
IncomeExpenseDetailsMapper incomeExpenseDetailsMapper;
@Resource
@InjectMocks
private OrganAmountServiceImpl organAmountService;
@MockitoBean
@Mock
private OrganService organService;
@MockitoBean
@Mock
private PurchaseService purchaseService;
@MockitoBean
@Mock
private InvoiceService invoiceService;
@Test
@@ -64,13 +58,13 @@ public class OrganAmountServiceImplTest extends BaseDbAndRedisUnitTest {
// ===== given =====
Long organId = SecurityFrameworkUtils.getUserOrganId();
PurchaseRecordDO record = new PurchaseRecordDO();
record.setEndTime(LocalDate.of(2025, 12, 31));
record.setInitial(false);
record.setPurchaseDuration(12);
record.setPurchaseDurationUnit(1);
PurchaseRecordDO recordDO = new PurchaseRecordDO();
recordDO.setEndTime(LocalDate.of(2025, 12, 31));
recordDO.setInitial(false);
recordDO.setPurchaseDuration(12);
recordDO.setPurchaseDurationUnit(1);
OrgEarliestPurchaseProductRespVO resp = new OrgEarliestPurchaseProductRespVO(record);
OrgEarliestPurchaseProductRespVO resp = new OrgEarliestPurchaseProductRespVO(recordDO);
when(purchaseService.getOrgEarliestProductDetail(organId))
.thenReturn(resp);
@@ -125,11 +119,11 @@ public class OrganAmountServiceImplTest extends BaseDbAndRedisUnitTest {
void testGetOrganProductOverview_initialPurchase() {
Long organId = SecurityFrameworkUtils.getUserOrganId();
PurchaseRecordDO record = new PurchaseRecordDO();
record.setEndTime(LocalDate.of(2025, 1, 1));
record.setInitial(true);
PurchaseRecordDO recordDO = new PurchaseRecordDO();
recordDO.setEndTime(LocalDate.of(2025, 1, 1));
recordDO.setInitial(true);
OrgEarliestPurchaseProductRespVO resp = new OrgEarliestPurchaseProductRespVO(record);
OrgEarliestPurchaseProductRespVO resp = new OrgEarliestPurchaseProductRespVO(recordDO);
when(purchaseService.getOrgEarliestProductDetail(organId))
.thenReturn(resp);
@@ -181,24 +175,23 @@ public class OrganAmountServiceImplTest extends BaseDbAndRedisUnitTest {
LocalDate.now().plusDays(1)
});
IncomeExpenseDetailsDO pojo1 = randomPojo(IncomeExpenseDetailsDO.class, o -> {
o.setOrganId(organId);
o.setAmount(new BigDecimal("100"));
o.setCreateTime(LocalDateTime.now().minusDays(2));
});
IncomeExpenseDetailsDO pojo2 = randomPojo(IncomeExpenseDetailsDO.class, o -> {
o.setOrganId(organId);
o.setAmount(new BigDecimal("200"));
o.setCreateTime(LocalDateTime.now());
});
IncomeExpenseDetailsDO pojo3 = randomPojo(IncomeExpenseDetailsDO.class, o -> {
o.setAmount(new BigDecimal("200"));
o.setCreateTime(LocalDateTime.now());
});
OrganAmountGroupByCreateTimeRespVO vo1 = new OrganAmountGroupByCreateTimeRespVO();
vo1.setDate("2026-1-14");
vo1.setAmount(new BigDecimal("100"));
incomeExpenseDetailsMapper.insert(pojo1);
incomeExpenseDetailsMapper.insert(pojo2);
incomeExpenseDetailsMapper.insert(pojo3);
OrganAmountGroupByCreateTimeRespVO vo2 = new OrganAmountGroupByCreateTimeRespVO();
vo2.setDate("2026-1-16");
vo2.setAmount(new BigDecimal("200"));
OrganAmountGroupByCreateTimeRespVO vo3 = new OrganAmountGroupByCreateTimeRespVO();
vo3.setDate("2026-1-15");
vo3.setAmount(new BigDecimal("200"));
List<OrganAmountGroupByCreateTimeRespVO> organAmountGroupByCreateTimeRespVOS = new ArrayList<>();
organAmountGroupByCreateTimeRespVOS.add(vo1);
organAmountGroupByCreateTimeRespVOS.add(vo2);
when(incomeExpenseDetailsMapper.selectOrganIncomeExpenseTrendGroupByCreateTime(reqVO, organId)).thenReturn(organAmountGroupByCreateTimeRespVOS);
// when query org
Map<String, Object> result =
@@ -215,14 +208,16 @@ public class OrganAmountServiceImplTest extends BaseDbAndRedisUnitTest {
assertArrayEquals(
new BigDecimal[]{
new BigDecimal("100.00"),
new BigDecimal("100"),
BigDecimal.ZERO,
new BigDecimal("200.00"),
new BigDecimal("200"),
BigDecimal.ZERO,
},
data
);
organAmountGroupByCreateTimeRespVOS.add(vo3);
when(incomeExpenseDetailsMapper.selectOrganIncomeExpenseTrendGroupByCreateTime(reqVO, null)).thenReturn(organAmountGroupByCreateTimeRespVOS);
// when not query org
result = organAmountService.getConsumptionTrend(reqVO, false);
@@ -237,9 +232,9 @@ public class OrganAmountServiceImplTest extends BaseDbAndRedisUnitTest {
assertArrayEquals(
new BigDecimal[]{
new BigDecimal("100.00"),
BigDecimal.ZERO,
new BigDecimal("400.00"),
new BigDecimal("100"),
new BigDecimal("200"),
new BigDecimal("200"),
BigDecimal.ZERO,
},
data
@@ -1,9 +1,12 @@
package com.cf.imes.module.system.service.funds.productpromotion;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.i18n.core.util.I18nUtils;
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.system.controller.admin.funds.productpromotion.vo.ProductPromotionPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.productpromotion.vo.ProductPromotionSaveReqVO;
import com.cf.imes.module.system.dal.dataobject.funds.productpromotion.ProductPromotionDO;
@@ -11,18 +14,15 @@ import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
import com.cf.imes.module.system.dal.mysql.funds.productpromotion.ProductPromotionMapper;
import com.cf.imes.module.system.enums.pay.DurationUnitEnum;
import com.cf.imes.module.system.service.funds.products.ProductsDetailService;
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.InjectMocks;
import org.mockito.Mock;
import java.time.LocalDateTime;
import java.util.List;
import static com.cf.imes.framework.common.util.object.ObjectUtils.cloneIgnoreId;
import static com.cf.imes.framework.test.core.util.AssertUtils.assertPojoEquals;
import static com.cf.imes.framework.test.core.util.AssertUtils.assertServiceException;
import static com.cf.imes.framework.test.core.util.RandomUtils.randomPojo;
@@ -33,34 +33,35 @@ 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.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* @author Gqr
* @since 2025/10/24 11:20
*/
@Import(ProductPromotionServiceImpl.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class ProductPromotionServiceImplTest extends BaseDbClearAfterClassAndRedisUnitTest {
@Resource
class ProductPromotionServiceImplTest extends BaseMockitoUnitTest {
@InjectMocks
private ProductPromotionServiceImpl productPromotionService;
@Resource
@Mock
private ProductPromotionMapper productPromotionMapper;
@MockitoBean
@Mock
private ProductsDetailService productsDetailService;
@MockitoBean
@Mock
private I18nUtils i18nUtils;
private static ProductPromotionDO createDO;
@BeforeAll
static void init(){
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), ProductPromotionDO.class);
}
@Test
@Order(1)
void testCreate() {
ProductPromotionSaveReqVO reqVO = randomPojo(ProductPromotionSaveReqVO.class, o -> {
o.setId(null);
o.setId(100L);
o.setActivityName("充值送活动");
o.setPurchaseDuration(1);
o.setPurchaseDurationUnit(DurationUnitEnum.YEAR.getCode());
@@ -76,27 +77,33 @@ class ProductPromotionServiceImplTest extends BaseDbClearAfterClassAndRedisUnitT
productsDO.setProductName("产品名称");
when(productsDetailService.validateProductExist(any())).thenReturn(productsDO);
Long id = productPromotionService.create(reqVO);
productPromotionService.create(reqVO);
// 校验数据库插入结果
createDO = productPromotionMapper.selectById(id);
assertNotNull(createDO);
assertEquals("充值送活动", createDO.getActivityName());
assertEquals(1, createDO.getPurchaseDuration());
assertEquals(DurationUnitEnum.YEAR.getCode(), createDO.getPurchaseDurationUnit());
assertEquals(1, createDO.getGiftDuration());
assertEquals(DurationUnitEnum.DAY.getCode(), createDO.getGiftDurationUnit());
// 验证插入
verify(productPromotionMapper).insert(argThat((ProductPromotionDO infoDO) ->
infoDO.getProductId().equals(productsDO.getId())
&& infoDO.getProductName().equals(productsDO.getProductName())
&& infoDO.getId().equals(100L)
&& infoDO.getActivityName().equals(reqVO.getActivityName())
&& infoDO.getPurchaseDuration().equals(reqVO.getPurchaseDuration())
&& infoDO.getPurchaseDurationUnit().equals(reqVO.getPurchaseDurationUnit())
&& infoDO.getGiftDuration().equals(reqVO.getGiftDuration())
&& infoDO.getGiftDurationUnit().equals(reqVO.getGiftDurationUnit())
));
// 再次插入相同活动名称,断言异常
when(productPromotionMapper.selectOne(any(LambdaQueryWrapperX.class))).thenReturn(new ProductPromotionDO());
assertServiceException(() -> productPromotionService.create(reqVO), PRODUCT_PROMOTION_ACTIVE_NAME_IS_EXIST);
// 再次插入相同产品-相同购买时长和单位,断言异常
reqVO.setActivityName("充值送活动1");
when(productPromotionMapper.selectOne(any(LambdaQueryWrapper.class))).thenReturn(null).thenReturn(new ProductPromotionDO());
when(i18nUtils.getMessage(anyString())).thenReturn("");
assertServiceException(() -> productPromotionService.create(reqVO), PRODUCT_PROMOTION_PURCHASEDURATION_IS_EXIST, reqVO.getPurchaseDuration(), DurationUnitEnum.getDesc(reqVO.getPurchaseDurationUnit()));
}
@Test
@Order(2)
void testUpdate_not_exist() {
ProductPromotionSaveReqVO reqVO = new ProductPromotionSaveReqVO();
reqVO.setId(321L);
@@ -111,50 +118,48 @@ class ProductPromotionServiceImplTest extends BaseDbClearAfterClassAndRedisUnitT
}
@Test
@Order(3)
void testUpdate() {
// 插入
ProductPromotionDO createDO1 = new ProductPromotionDO();
createDO1.setId(null);
createDO1.setActivityName("充值送活动新");
createDO1.setPurchaseDuration(1);
createDO1.setPurchaseDurationUnit(DurationUnitEnum.YEAR.getCode());
createDO1.setProductId(2L);
createDO1.setProductName("产品名称2");
createDO1.setGiftDuration(1);
createDO1.setGiftDurationUnit(DurationUnitEnum.DAY.getCode());
createDO1.setStartTime(LocalDateTime.now());
createDO1.setEndTime(LocalDateTime.now().plusDays(1));
productPromotionMapper.insert(createDO1);
ProductPromotionSaveReqVO reqVO = new ProductPromotionSaveReqVO();
reqVO.setId(createDO1.getId());
reqVO.setId(100L);
reqVO.setActivityName("充值送活动");
assertServiceException(() -> productPromotionService.update(reqVO),
PRODUCT_PROMOTION_ACTIVE_NAME_IS_EXIST);
reqVO.setPurchaseDuration(1);
reqVO.setPurchaseDurationUnit(DurationUnitEnum.YEAR.getCode());
ProductsDO productsDO = new ProductsDO();
productsDO.setId(2L);
productsDO.setProductName("产品名称2");
when(productsDetailService.validateProductExist(any())).thenReturn(productsDO);
// 再次插入相同活动名称,断言异常
when(productPromotionMapper.selectOne(any(LambdaQueryWrapperX.class))).thenReturn(new ProductPromotionDO()).thenReturn(new ProductPromotionDO());
assertServiceException(() -> productPromotionService.update(reqVO), PRODUCT_PROMOTION_ACTIVE_NAME_IS_EXIST);
// 再次插入相同产品-相同购买时长和单位,断言异常
reqVO.setActivityName("充值送活动1");
when(productPromotionMapper.selectOne(any(LambdaQueryWrapper.class))).thenReturn(new ProductPromotionDO()).thenReturn(null).thenReturn(new ProductPromotionDO());
when(i18nUtils.getMessage(anyString())).thenReturn("");
assertServiceException(() -> productPromotionService.update(reqVO), PRODUCT_PROMOTION_PURCHASEDURATION_IS_EXIST, reqVO.getPurchaseDuration(), DurationUnitEnum.getDesc(reqVO.getPurchaseDurationUnit()));
// 更新成功
ProductPromotionSaveReqVO update = BeanUtil.copyProperties(createDO1, ProductPromotionSaveReqVO.class);
assertDoesNotThrow(() -> productPromotionService.update(update));
when(productPromotionMapper.selectOne(any(LambdaQueryWrapper.class))).thenReturn(new ProductPromotionDO()).thenReturn(null).thenReturn(null);
productPromotionService.update(reqVO);
// 验证数据库更新
verify(productPromotionMapper).updateById(argThat((ProductPromotionDO productPromotionDO) ->
productPromotionDO.getProductId().equals(productsDO.getId())
&& productPromotionDO.getProductName().equals(productsDO.getProductName())
&& productPromotionDO.getId().equals(reqVO.getId())
&& productPromotionDO.getActivityName().equals(reqVO.getActivityName())
));
}
@Test
@Order(3)
void testGet_not_exist() {
assertServiceException(() -> productPromotionService.get(null), PRODUCT_PROMOTION_NO_EXIST);
}
@Test
@Order(5)
void testGetPage_success() {
ProductPromotionDO detail = randomPojo(ProductPromotionDO.class, o -> {
o.setId(null);
@@ -166,23 +171,6 @@ class ProductPromotionServiceImplTest extends BaseDbClearAfterClassAndRedisUnitT
o.setRemark("晨丰备注1");
});
productPromotionMapper.insert(detail);
// 不匹配 ActivityName
productPromotionMapper.insert(cloneIgnoreId(detail, o -> o.setActivityName("新分页活动")));
// 不匹配 RechargeGiftType
productPromotionMapper.insert(cloneIgnoreId(detail, o -> o.setPurchaseDuration(4)));
// 不匹配 GiftAmount
productPromotionMapper.insert(cloneIgnoreId(detail, o -> o.setGiftDuration(5)));
// 不匹配 RechargeAmount
productPromotionMapper.insert(cloneIgnoreId(detail, o -> o.setRemark("晨丰备1注")));
// 被逻辑删除
productPromotionMapper.insert(cloneIgnoreId(detail, o -> o.setDeleted(true)));
// ============ 构造查询参数 ============
ProductPromotionPageReqVO reqVO = new ProductPromotionPageReqVO();
reqVO.setActivityName("晨丰");
@@ -192,6 +180,8 @@ class ProductPromotionServiceImplTest extends BaseDbClearAfterClassAndRedisUnitT
reqVO.setPageNo(1);
reqVO.setPageSize(10);
when(productPromotionMapper.selectPage(reqVO)).thenReturn(new PageResult<>(List.of(detail), 1L));
// ============ 调用方法 ============
PageResult<ProductPromotionDO> pageResult = productPromotionService.getPage(reqVO);
@@ -202,27 +192,30 @@ class ProductPromotionServiceImplTest extends BaseDbClearAfterClassAndRedisUnitT
}
@Test
@Order(6)
void testDelete() {
assertDoesNotThrow(() -> productPromotionService.delete(createDO.getId()));
ProductPromotionDO exist = randomPojo(ProductPromotionDO.class);
when(productPromotionMapper.selectOne(any(LambdaQueryWrapperX.class))).thenReturn(exist);
assertDoesNotThrow(() -> productPromotionService.delete(exist.getId()));
verify(productPromotionMapper, times(1)).deleteById(exist.getId());
}
@Test
@Order(7)
void testDelete_not_exist() {
assertServiceException(() -> productPromotionService.delete(null), PRODUCT_PROMOTION_NO_EXIST);
assertServiceException(() -> productPromotionService.delete(321L), PRODUCT_PROMOTION_NO_EXIST);
}
@Test
@Order(8)
void testGetAvailableRechargeActiveList() {
// 当前时间
LocalDateTime now = LocalDateTime.now();
Long productId = 1000L;
// 1️⃣ 有效活动(时间区间内)
// 有效活动(时间区间内)
ProductPromotionDO valid = new ProductPromotionDO();
valid.setActivityName("有效活动");
valid.setProductId(productId);
@@ -236,54 +229,25 @@ class ProductPromotionServiceImplTest extends BaseDbClearAfterClassAndRedisUnitT
valid.setDeleted(false);
productPromotionMapper.insert(valid);
// 2️⃣ 未开始活动
ProductPromotionDO notStarted = new ProductPromotionDO();
notStarted.setActivityName("未开始活动");
notStarted.setProductId(productId);
notStarted.setProductName("产品名称");
notStarted.setPurchaseDuration(2);
notStarted.setPurchaseDurationUnit(DurationUnitEnum.YEAR.getCode());
notStarted.setGiftDuration(2);
notStarted.setGiftDurationUnit(DurationUnitEnum.DAY.getCode());
notStarted.setStartTime(now.plusDays(1));
notStarted.setEndTime(now.plusDays(2));
notStarted.setDeleted(false);
productPromotionMapper.insert(notStarted);
// 3️⃣ 已过期活动
ProductPromotionDO expired = new ProductPromotionDO();
expired.setActivityName("已过期活动");
expired.setProductId(productId);
expired.setProductName("产品名称");
expired.setPurchaseDuration(3);
expired.setPurchaseDurationUnit(DurationUnitEnum.YEAR.getCode());
expired.setGiftDuration(3);
expired.setGiftDurationUnit(DurationUnitEnum.DAY.getCode());
expired.setStartTime(now.minusDays(5));
expired.setEndTime(now.minusDays(1));
expired.setDeleted(false);
productPromotionMapper.insert(expired);
// 4️⃣ 被逻辑删除的活动
ProductPromotionDO deleted = new ProductPromotionDO();
deleted.setActivityName("被删除活动");
deleted.setProductId(productId);
deleted.setProductName("产品名称");
deleted.setPurchaseDuration(4);
deleted.setPurchaseDurationUnit(DurationUnitEnum.YEAR.getCode());
deleted.setGiftDuration(4);
deleted.setGiftDurationUnit(DurationUnitEnum.DAY.getCode());
deleted.setStartTime(now.minusDays(1));
deleted.setEndTime(now.plusDays(1));
deleted.setDeleted(true);
productPromotionMapper.insert(deleted);
when(productPromotionMapper.selectList(any(LambdaQueryWrapper.class))).thenReturn(List.of(valid));
// 执行被测方法
List<ProductPromotionDO> result = productPromotionService.getAvailableProductPromotionList(productId);
// 验证结果
assertEquals(1, result.size(), "只应返回一个有效活动");
assertEquals("有效活动", result.get(0).getActivityName());
// then
assertNotNull(result);
assertEquals(1L, result.size());
// 校验 查询条件
verify(productPromotionMapper).selectList(
argThat((LambdaQueryWrapper wrapper) ->
wrapper.getSqlSegment().contains("deleted")
&& wrapper.getSqlSegment().contains("product_id")
&& wrapper.getSqlSegment().contains("start_time")
&& wrapper.getSqlSegment().contains("end_time")
)
);
}
}
@@ -1,8 +1,12 @@
package com.cf.imes.module.system.service.funds.products;
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.util.i18n.core.util.I18nUtils;
import com.cf.imes.framework.test.core.ut.BaseDbAndRedisUnitTest;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest;
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsSaveReqVO;
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
@@ -11,14 +15,15 @@ import com.cf.imes.module.system.dal.mysql.funds.products.ProductsDetailMapper;
import com.cf.imes.module.system.dal.mysql.funds.products.ProductsMapper;
import com.cf.imes.module.system.enums.pay.ProductDurationUnitEnum;
import com.cf.imes.module.system.enums.products.ProductStatusEnum;
import jakarta.annotation.Resource;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.math.BigDecimal;
import java.util.List;
import static com.cf.imes.framework.common.util.object.ObjectUtils.cloneIgnoreId;
import static com.cf.imes.framework.test.core.util.AssertUtils.assertPojoEquals;
import static com.cf.imes.framework.test.core.util.AssertUtils.assertServiceException;
import static com.cf.imes.framework.test.core.util.RandomUtils.randomPojo;
@@ -31,26 +36,35 @@ 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.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* @author Gqr
* @since 2025/10/14 13:48
*/
@Import(ProductsDetailServiceImpl.class)
public class ProductsDetailServiceImplTest extends BaseDbAndRedisUnitTest {
@Resource
class ProductsDetailServiceImplTest extends BaseMockitoUnitTest {
@InjectMocks
private ProductsDetailServiceImpl productsDetailService;
@Resource
@Mock
private ProductsDetailMapper productsDetailMapper;
@MockitoBean
@Mock
private ProductsMapper productsMapper;
@MockitoBean
@Mock
private I18nUtils i18nUtils;
@BeforeAll
static void init(){
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), ProductsDetailDO.class);
}
@Test
void testCreateProductDetails() {
// mock下架状态的产品
@@ -62,16 +76,30 @@ public class ProductsDetailServiceImplTest extends BaseDbAndRedisUnitTest {
when(productsMapper.selectOne(any())).thenReturn(mockProduct);
ProductDetailsSaveReqVO productDetailsSaveReqVO = randomPojo(ProductDetailsSaveReqVO.class, p -> {
p.setId(null);
p.setDiscount(BigDecimal.valueOf(10));
p.setDuration(ProductDurationUnitEnum.YEAR.getCode());
p.setProductId(mockProduct.getId());
});
// 模拟 Mapper 插入时生成 ID
doAnswer(invocation -> {
ProductsDetailDO detail = invocation.getArgument(0);
detail.setId(100L); // 模拟自增主键
return null;
}).when(productsDetailMapper).insert(any(ProductsDetailDO.class));
// 调用
Long id = productsDetailService.create(productDetailsSaveReqVO);
// 断言
assertNotNull(id);
// 校验记录的属性是否正确
ProductsDetailDO productsDetailDO = productsDetailMapper.selectById(id);
assertPojoEquals(productDetailsSaveReqVO, productsDetailDO, "id");
assertEquals(100L,id);
// 验证 Mapper 方法被调用一次
verify(productsDetailMapper, times(1)).insert(argThat((ProductsDetailDO detail) ->
detail.getDiscount().equals(productDetailsSaveReqVO.getDiscount())
&& detail.getDuration().equals(productDetailsSaveReqVO.getDuration())
&& detail.getProductId().equals(mockProduct.getId())
));
}
@Test
@@ -99,20 +127,18 @@ public class ProductsDetailServiceImplTest extends BaseDbAndRedisUnitTest {
mockProduct.setStatus(ProductStatusEnum.PRODUCT_DELIS.getStatus());
when(productsMapper.selectOne(any())).thenReturn(mockProduct);
// 插入一条与 createReqVO 冲突的数据
ProductsDetailDO existing = new ProductsDetailDO();
existing.setProductId(1L);
existing.setDuration(12);
existing.setDurationUnit(0);
existing.setDeleted(false);
productsDetailMapper.insert(existing);
// 模拟新增同样 duration + unit 的记录
ProductDetailsSaveReqVO reqVO = new ProductDetailsSaveReqVO()
.setProductId(existing.getProductId())
.setDuration(existing.getDuration())
.setDurationUnit(existing.getDurationUnit());
.setId(999L)
.setProductId(123L)
.setDuration(1)
.setDurationUnit(ProductDurationUnitEnum.MONTH.getCode());
// mock重复存在
when(productsDetailMapper.selectCountByDuration(reqVO.getProductId(), reqVO.getId(), reqVO.getDuration(), reqVO.getDurationUnit())).thenReturn(1);
when(i18nUtils.getMessage(anyString())).thenReturn("");
assertServiceException(() -> productsDetailService.create(reqVO),
PRODUCTS_DETAIL_DURATION_EXIST, reqVO.getDuration(), ProductDurationUnitEnum.getDesc(reqVO.getDurationUnit()));
}
@@ -127,12 +153,14 @@ public class ProductsDetailServiceImplTest extends BaseDbAndRedisUnitTest {
when(productsMapper.selectOne(any())).thenReturn(mockProduct);
// mock exist
ProductsDetailDO detail = new ProductsDetailDO();
detail.setId(999L);
detail.setProductId(mockProduct.getId());
detail.setDuration(12);
detail.setDurationUnit(1);
detail.setDeleted(false);
productsDetailMapper.insert(detail);
when(productsDetailMapper.selectOne(any(LambdaQueryWrapperX.class))).thenReturn(detail);
// 构造请求
ProductDetailsSaveReqVO reqVO = new ProductDetailsSaveReqVO()
@@ -144,13 +172,17 @@ public class ProductsDetailServiceImplTest extends BaseDbAndRedisUnitTest {
// 调用
productsDetailService.update(reqVO);
// 验证结果
ProductsDetailDO updated = productsDetailMapper.selectById(detail.getId());
assertEquals(6, updated.getDuration());
// 校验状态更新
verify(productsDetailMapper).update(argThat((LambdaUpdateWrapper wrapper) ->
wrapper.getSqlSegment().contains("id")
&& wrapper.getSqlSet().contains("discount")
&& wrapper.getSqlSet().contains("duration")
&& wrapper.getSqlSet().contains("duration_unit")
));
}
@Test
void deleteTest(){
void deleteTest() {
// mock下架状态的产品
ProductsDO mockProduct = new ProductsDO();
mockProduct.setId(123L);
@@ -160,11 +192,12 @@ public class ProductsDetailServiceImplTest extends BaseDbAndRedisUnitTest {
when(productsMapper.selectOne(any())).thenReturn(mockProduct);
ProductsDetailDO detail = new ProductsDetailDO();
detail.setId(999L);
detail.setProductId(mockProduct.getId());
detail.setDuration(12);
detail.setDurationUnit(1);
detail.setDeleted(false);
productsDetailMapper.insert(detail);
when(productsDetailMapper.selectOne(any(LambdaQueryWrapperX.class))).thenReturn(detail);
// 调用删除
productsDetailService.delete(detail.getId());
@@ -180,7 +213,7 @@ public class ProductsDetailServiceImplTest extends BaseDbAndRedisUnitTest {
detail.setId(321L);
detail.setDeleted(false);
detail.setProductId(123L);
productsDetailMapper.insert(detail);
when(productsDetailMapper.selectOne(any(LambdaQueryWrapperX.class))).thenReturn(detail);
ProductsDetailDO result = productsDetailService.get(detail.getId());
assertNotNull(result);
@@ -198,20 +231,6 @@ public class ProductsDetailServiceImplTest extends BaseDbAndRedisUnitTest {
o.setDeleted(false);
});
productsDetailMapper.insert(detail);
// 不匹配 productId
productsDetailMapper.insert(cloneIgnoreId(detail, o -> o.setProductId(321L)));
// 不匹配 duration
productsDetailMapper.insert(cloneIgnoreId(detail, o -> o.setDuration(2)));
// 不匹配 discount
productsDetailMapper.insert(cloneIgnoreId(detail, o -> o.setDiscount(BigDecimal.valueOf(99))));
// 被逻辑删除
productsDetailMapper.insert(cloneIgnoreId(detail, o -> o.setDeleted(true)));
// ============ 构造查询参数 ============
ProductDetailsPageReqVO reqVO = new ProductDetailsPageReqVO();
reqVO.setProductId(123L);
@@ -219,6 +238,7 @@ public class ProductsDetailServiceImplTest extends BaseDbAndRedisUnitTest {
reqVO.setDiscount(BigDecimal.valueOf(100));
reqVO.setPageNo(1);
reqVO.setPageSize(10);
when(productsDetailMapper.selectPage(reqVO)).thenReturn(new PageResult<>(List.of(detail), 1L));
// ============ 调用方法 ============
PageResult<ProductsDetailDO> pageResult = productsDetailService.getPage(reqVO);
@@ -284,7 +304,7 @@ public class ProductsDetailServiceImplTest extends BaseDbAndRedisUnitTest {
detailDO.setDuration(1);
detailDO.setDurationUnit(ProductDurationUnitEnum.YEAR.getCode());
detailDO.setDiscount(BigDecimal.valueOf(85));
productsDetailMapper.insert(detailDO);
when(productsDetailMapper.selectOne(any())).thenReturn(detailDO);
BigDecimal discount = productsDetailService.getProductDetailOneYearDiscount(1L);
assertEquals(BigDecimal.valueOf(85), discount);
@@ -1,19 +1,25 @@
package com.cf.imes.module.system.service.funds.products;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.test.core.ut.BaseDbAndRedisUnitTest;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.mybatis.core.query.LambdaUpdateWrapperX;
import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest;
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductSaveReqVO;
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
import com.cf.imes.module.system.dal.mysql.funds.products.ProductsMapper;
import com.cf.imes.module.system.enums.products.ProductStatusEnum;
import jakarta.annotation.Resource;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.math.BigDecimal;
import java.util.List;
import static com.cf.imes.framework.common.util.object.ObjectUtils.cloneIgnoreId;
import static com.cf.imes.framework.test.core.util.AssertUtils.assertPojoEquals;
import static com.cf.imes.framework.test.core.util.AssertUtils.assertServiceException;
import static com.cf.imes.framework.test.core.util.RandomUtils.randomLongId;
@@ -23,23 +29,26 @@ import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCTS_IS_EXI
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCTS_NO_DELETE;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCTS_NO_EXIST;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCTS_NO_UPDATE;
import static org.assertj.core.api.Assertions.assertThat;
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.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* @author Gqr
* @since 2025/10/14 9:46
*/
@Import(ProductsServiceImpl.class)
public class ProductsServiceImplTest extends BaseDbAndRedisUnitTest {
@Resource
class ProductsServiceImplTest extends BaseMockitoUnitTest {
@InjectMocks
private ProductsServiceImpl productsService;
@Resource
@Mock
private ProductsMapper productsMapper;
@BeforeAll
static void init(){
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), ProductsDO.class);
}
@Test
void testCreateProductSuccess() {
// 构造请求对象
@@ -50,14 +59,15 @@ public class ProductsServiceImplTest extends BaseDbAndRedisUnitTest {
req.setStatus(ProductStatusEnum.PRODUCT_UPDATES.getStatus());
// 调用真实 Service 方法
Long id = productsService.create(req);
productsService.create(req);
// 校验数据库插入结果
ProductsDO result = productsMapper.selectById(id);
assertNotNull(result);
assertEquals(productName, result.getProductName());
assertEquals(new BigDecimal("88.88"), result.getPrice());
assertEquals(ProductStatusEnum.PRODUCT_UPDATES.getStatus(), result.getStatus());
// 校验插入
verify(productsMapper).insert(argThat((ProductsDO infoDO) ->
infoDO.getProductName().equals(req.getProductName())
&& infoDO.getPrice().equals(req.getPrice())
&& infoDO.getSoftwareId().equals(0)
&& infoDO.getStatus().equals(req.getStatus())
));
}
/**
@@ -65,15 +75,12 @@ public class ProductsServiceImplTest extends BaseDbAndRedisUnitTest {
*/
@Test
void testUpdate_takeoff_to_listed() {
ProductSaveReqVO createVO = new ProductSaveReqVO();
String productName = randomString();
createVO.setProductName(productName);
createVO.setPrice(new BigDecimal("88.88"));
createVO.setStatus(ProductStatusEnum.PRODUCT_DELIS.getStatus());
Long id = productsService.create(createVO);
ProductsDO productsDO = new ProductsDO();
productsDO.setStatus(ProductStatusEnum.PRODUCT_DELIS.getStatus());
when(productsMapper.selectOne(any(LambdaQueryWrapperX.class))).thenReturn(productsDO);
ProductSaveReqVO updateVO = new ProductSaveReqVO();
updateVO.setId(id);
updateVO.setId(100L);
String newProductName = randomString();
updateVO.setProductName(newProductName);
updateVO.setStatus(ProductStatusEnum.PRODUCT_UPDATES.getStatus());
@@ -81,10 +88,13 @@ public class ProductsServiceImplTest extends BaseDbAndRedisUnitTest {
productsService.update(updateVO);
ProductsDO db = productsMapper.selectById(id);
assertThat(db.getProductName()).isEqualTo(newProductName);
assertThat(db.getPrice()).isEqualByComparingTo("199.99");
assertEquals(ProductStatusEnum.PRODUCT_UPDATES.getStatus(), db.getStatus());
// 校验状态更新
verify(productsMapper).update(argThat((LambdaUpdateWrapperX wrapper) ->
wrapper.getSqlSegment().contains("id")
&& wrapper.getSqlSet().contains("product_name")
&& wrapper.getSqlSet().contains("price")
&& wrapper.getSqlSet().contains("status")
));
}
/**
@@ -92,13 +102,12 @@ public class ProductsServiceImplTest extends BaseDbAndRedisUnitTest {
*/
@Test
void testUpdate_statusUpdatableThrowsException() {
ProductSaveReqVO dbProduct = new ProductSaveReqVO();
dbProduct.setProductName("产品");
dbProduct.setStatus(ProductStatusEnum.PRODUCT_UPDATES.getStatus());
Long id = productsService.create(dbProduct);
ProductsDO productsDO = new ProductsDO();
productsDO.setStatus(ProductStatusEnum.PRODUCT_UPDATES.getStatus());
when(productsMapper.selectOne(any(LambdaQueryWrapperX.class))).thenReturn(productsDO);
ProductSaveReqVO reqVO = new ProductSaveReqVO();
reqVO.setId(id);
reqVO.setId(100L);
reqVO.setStatus(ProductStatusEnum.PRODUCT_UPDATES.getStatus()); // 非下架
assertServiceException(() -> productsService.update(reqVO),
@@ -110,15 +119,12 @@ public class ProductsServiceImplTest extends BaseDbAndRedisUnitTest {
*/
@Test
void testUpdate_listed_to_takeoff() {
ProductSaveReqVO createVO = new ProductSaveReqVO();
String productName = randomString();
createVO.setProductName(productName);
createVO.setPrice(new BigDecimal("88.88"));
createVO.setStatus(ProductStatusEnum.PRODUCT_UPDATES.getStatus());
Long id = productsService.create(createVO);
ProductsDO productsDO = new ProductsDO();
productsDO.setStatus(ProductStatusEnum.PRODUCT_UPDATES.getStatus());
when(productsMapper.selectOne(any(LambdaQueryWrapperX.class))).thenReturn(productsDO);
ProductSaveReqVO updateVO = new ProductSaveReqVO();
updateVO.setId(id);
updateVO.setId(100L);
String newProductName = randomString();
updateVO.setProductName(newProductName);
updateVO.setStatus(ProductStatusEnum.PRODUCT_DELIS.getStatus());
@@ -126,50 +132,52 @@ public class ProductsServiceImplTest extends BaseDbAndRedisUnitTest {
productsService.update(updateVO);
ProductsDO db = productsMapper.selectById(id);
assertThat(db.getProductName()).isEqualTo(newProductName);
assertThat(db.getPrice()).isEqualByComparingTo("199.99");
assertEquals(ProductStatusEnum.PRODUCT_DELIS.getStatus(), db.getStatus());
// 校验状态更新
verify(productsMapper).update(argThat((LambdaUpdateWrapperX wrapper) ->
wrapper.getSqlSegment().contains("id")
&& wrapper.getSqlSet().contains("product_name")
&& wrapper.getSqlSet().contains("price")
&& wrapper.getSqlSet().contains("status")
));
}
@Test
void testDelete() {
ProductSaveReqVO createVO = new ProductSaveReqVO();
createVO.setProductName(randomString());
createVO.setPrice(new BigDecimal("88.88"));
createVO.setStatus(ProductStatusEnum.PRODUCT_DELIS.getStatus());
Long id = productsService.create(createVO);
ProductsDO productsDO = new ProductsDO();
productsDO.setId(100L);
productsDO.setStatus(ProductStatusEnum.PRODUCT_DELIS.getStatus());
when(productsMapper.selectOne(any(LambdaQueryWrapperX.class))).thenReturn(productsDO);
productsService.delete(id);
productsService.delete(productsDO.getId());
// 断言不存在了
assertNull(productsMapper.selectById(id));
assertNull(productsMapper.selectById(productsDO.getId()));
}
@Test
void testDelete_listed() {
ProductSaveReqVO createVO = new ProductSaveReqVO();
createVO.setProductName(randomString());
createVO.setPrice(new BigDecimal("88.88"));
createVO.setStatus(ProductStatusEnum.PRODUCT_UPDATES.getStatus());
Long id = productsService.create(createVO);
ProductsDO productsDO = new ProductsDO();
productsDO.setId(100L);
productsDO.setStatus(ProductStatusEnum.PRODUCT_UPDATES.getStatus());
when(productsMapper.selectOne(any(LambdaQueryWrapperX.class))).thenReturn(productsDO);
assertServiceException(() -> productsService.delete(id),
assertServiceException(() -> productsService.delete(productsDO.getId()),
PRODUCTS_NO_DELETE);
}
@Test
void testGet() {
ProductSaveReqVO createVO = new ProductSaveReqVO();
String productName = randomString();
createVO.setProductName(productName);
createVO.setPrice(new BigDecimal("88.88"));
createVO.setStatus(1);
Long id = productsService.create(createVO);
ProductsDO db = productsService.get(id);
ProductsDO productsDO = new ProductsDO();
productsDO.setId(100L);
productsDO.setProductName("产品名称");
productsDO.setStatus(ProductStatusEnum.PRODUCT_UPDATES.getStatus());
when(productsMapper.selectOne(any(LambdaQueryWrapperX.class))).thenReturn(productsDO);
assertThat(db).isNotNull();
assertThat(db.getProductName()).isEqualTo(productName);
ProductsDO db = productsService.get(productsDO.getId());
assertEquals(db.getId(), productsDO.getId());
assertEquals(db.getProductName(), productsDO.getProductName());
assertEquals(db.getStatus(), productsDO.getStatus());
}
@Test
@@ -181,16 +189,6 @@ public class ProductsServiceImplTest extends BaseDbAndRedisUnitTest {
o.setDeleted(false);
o.setPrice(new BigDecimal("99.99"));
});
productsMapper.insert(dbProduct);
// 不匹配 productName
productsMapper.insert(cloneIgnoreId(dbProduct, o -> o.setProductName("测试产品")));
// 不匹配 status
productsMapper.insert(cloneIgnoreId(dbProduct, o -> o.setStatus(ProductStatusEnum.PRODUCT_DELIS.getStatus())));
// 被逻辑删除
productsMapper.insert(cloneIgnoreId(dbProduct, o -> o.setDeleted(true)));
// ============ 构造查询参数 ============
ProductPageReqVO reqVO = new ProductPageReqVO();
@@ -199,6 +197,8 @@ public class ProductsServiceImplTest extends BaseDbAndRedisUnitTest {
reqVO.setPageNo(1);
reqVO.setPageSize(10);
when(productsService.getPage(reqVO)).thenReturn(new PageResult<>(List.of(dbProduct), 1L));
// ============ 调用方法 ============
PageResult<ProductsDO> pageResult = productsService.getPage(reqVO);
@@ -211,19 +211,14 @@ public class ProductsServiceImplTest extends BaseDbAndRedisUnitTest {
@Test
void testDuplicateNameThrowsException() {
when(productsMapper.selectList(any(LambdaQueryWrapperX.class))).thenReturn(List.of(new ProductsDO()));
ProductSaveReqVO createVO = new ProductSaveReqVO();
String productName = randomString();
createVO.setProductName(productName);
createVO.setPrice(new BigDecimal("88.88"));
createVO.setStatus(1);
productsService.create(createVO);
ProductSaveReqVO dup = new ProductSaveReqVO();
dup.setProductName(productName);
dup.setStatus(1);
dup.setPrice(new BigDecimal("50.00"));
assertServiceException(() -> productsService.create(dup),
assertServiceException(() -> productsService.create(createVO),
PRODUCTS_IS_EXIST, productName);
}
@@ -1,10 +1,12 @@
package com.cf.imes.module.system.service.funds.purchase;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.exception.ServiceException;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.test.core.ut.BaseDbAndRedisUnitTest;
import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest;
import com.cf.imes.module.system.controller.admin.funds.delay.vo.ProductDelayRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.TotalSalesAmountRespVO;
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsRespVO;
@@ -31,10 +33,12 @@ import com.cf.imes.module.system.service.funds.productpromotion.ProductPromotion
import com.cf.imes.module.system.service.funds.products.ProductsDetailService;
import com.cf.imes.module.system.service.organ.OrganService;
import com.cf.imes.framework.common.util.i18n.core.util.I18nUtils;
import jakarta.annotation.Resource;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
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 java.math.BigDecimal;
import java.time.LocalDate;
@@ -45,6 +49,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
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.ORG_PRODUCT_PURCHASE_EXIST_ERROR;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ORG_PRODUCT_PURCHASE_NOT_EXIST_ERROR;
@@ -56,40 +61,48 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@Import(PurchaseServiceImpl.class)
class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
class PurchaseServiceImplTest extends BaseMockitoUnitTest {
@Resource
@InjectMocks
private PurchaseServiceImpl purchaseService;
@Resource
@Mock
private PurchaseRecordMapper purchaseRecordMapper;
@MockitoBean
@Mock
private OrganService organService;
@MockitoBean
@Mock
private I18nUtils i18nUtils;
@MockitoBean
@Mock
private ProductsDetailService productsDetailService;
@MockitoBean
@Mock
private ProductDelayService productDelayService;
@MockitoBean
@Mock
private ProductPromotionService productPromotionService;
@MockitoBean
@Mock
private MybatisIdProperties mybatisIdProperties;
@BeforeAll
static void init(){
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), PurchaseRecordDO.class);
}
@Test
void testCreateAndGetAndDeleteRecord() {
// 准备参数
PurchaseRecordDO invoiceRecordsDO = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(1L);
o.setProductId(100L);
o.setCreateTime(LocalDateTime.now());
o.setExternalSpent(new BigDecimal("100.00"));
o.setProductName("测试产品");
@@ -99,8 +112,30 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
o.setInitial(false);
o.setOrganId(1L);
});
// when
purchaseService.createRecord(invoiceRecordsDO);
// then
ArgumentCaptor<PurchaseRecordDO> captor =
ArgumentCaptor.forClass(PurchaseRecordDO.class);
verify(purchaseRecordMapper).insert(captor.capture());
PurchaseRecordDO actual = captor.getValue();
assertEquals(1L, actual.getOrganId());
assertEquals(100L, actual.getProductId());
}
@Test
void testGet(){
PurchaseRecordDO invoiceRecordsDO = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(1L);
o.setProductId(100L);
o.setTotalAmount(new BigDecimal("200.00"));
});
when(purchaseRecordMapper.selectById(anyLong())).thenReturn(invoiceRecordsDO);
// 查询
PurchaseRecordDO result = purchaseService.getRecord(1L);
@@ -108,31 +143,42 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
assertNotNull(result);
assertEquals(invoiceRecordsDO.getProductName(), result.getProductName());
assertEquals(invoiceRecordsDO.getTotalAmount(), result.getTotalAmount());
}
// 更新为可开票
purchaseService.updateRecordInvoicable(1L, invoiceRecordsDO.getOrganId());
@Test
void testUpdateReocrdInvoicable(){
Long purchaseRecordId = 100L;
Long organId = 200L;
// 查询
result = purchaseService.getRecord(1L);
// when
purchaseService.updateRecordInvoicable(purchaseRecordId, organId);
// 校验更新
assertNotNull(result);
assertEquals(result.getIsInvocing(), INVOICABLE.getCode());
// 校验状态更新
verify(purchaseRecordMapper).update(argThat((LambdaUpdateWrapper wrapper) ->
wrapper.getSqlSegment().contains("id")
&& wrapper.getSqlSegment().contains("organ_id")
&& wrapper.getSqlSet().contains("is_invocing")
));
}
// 删除
purchaseService.deleteRecord(1L);
@Test
void testDelete(){
purchaseService.deleteRecord(100L);
// 查询
result = purchaseService.getRecord(1L);
// 验证删除
assertNull(result);
// 校验状态更新
verify(purchaseRecordMapper).update(argThat((LambdaUpdateWrapper wrapper) ->
wrapper.getSqlSegment().contains("id")
&& wrapper.getSqlSet().contains("deleted")
&& wrapper.getSqlSet().contains("status")
));
}
@Test
void testGetPurchaseRecord_emptyResult() {
PurchaseRecordPageReqVO pageReqVO = new PurchaseRecordPageReqVO();
when(purchaseRecordMapper.selectPage(pageReqVO)).thenReturn(new PageResult<>(null, 0L));
PageResult<PurchaseRecordRespVO> result =
purchaseService.getPurchaseRecord(pageReqVO);
@@ -154,11 +200,11 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
o.setInitial(false);
o.setOrganId(1L);
});
purchaseRecordMapper.insert(recordDO);
PurchaseRecordPageReqVO pageReqVO = new PurchaseRecordPageReqVO();
pageReqVO.setEndTime(new LocalDate[]{LocalDate.now()}); // length != 2
when(purchaseRecordMapper.selectPage(pageReqVO)).thenReturn(new PageResult(List.of(recordDO), 1l));
when(i18nUtils.getMessage(anyString())).thenReturn("支付宝");
when(organService.getOrganWithDeleted(anyLong())).thenReturn(null);
@@ -184,14 +230,13 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
o.setInitial(false);
o.setOrganId(2L);
});
purchaseRecordMapper.insert(recordDO);
PurchaseRecordPageReqVO pageReqVO = new PurchaseRecordPageReqVO();
pageReqVO.setEndTime(new LocalDate[]{
LocalDate.now().minusDays(1),
LocalDate.now()
});
when(purchaseRecordMapper.selectPage(pageReqVO)).thenReturn(new PageResult(List.of(recordDO), 1l));
when(i18nUtils.getMessage(anyString())).thenReturn("支付宝");
OrganizationDO organ = new OrganizationDO();
@@ -233,7 +278,7 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
o.setOrganId(organId);
o.setEndTime(LocalDate.now().plusDays(30));
});
purchaseRecordMapper.insert(recordDO);
when(purchaseRecordMapper.selectOne(any())).thenReturn(recordDO);
// mock:无延期记录
when(productDelayService.getRecordsByPurchaseId(recordDO.getId(), organId))
@@ -269,7 +314,7 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
o.setOrganId(organId);
o.setEndTime(originalEndTime);
});
purchaseRecordMapper.insert(recordDO);
when(purchaseRecordMapper.selectOne(any())).thenReturn(recordDO);
// mock 延期记录(第一条为最新)
ProductDelayRespVO delayVO = new ProductDelayRespVO();
@@ -290,22 +335,11 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
@Test
void getInvoicingAmountTest(){
// 准备参数
PurchaseRecordDO recordDO = randomPojo(PurchaseRecordDO.class, o -> {
o.setCreateTime(LocalDateTime.now());
o.setExternalSpent(new BigDecimal("100.00"));
o.setProductName("测试产品");
o.setTotalAmount(new BigDecimal("200.00"));
o.setStatus(PurchaseRecordStatusEnum.ACTIVE.getStatus());
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(INVOICABLE.getCode());
o.setInitial(false);
o.setOrganId(1L);
});
purchaseRecordMapper.insert(recordDO);
BigDecimal amount = new BigDecimal(100);
when(purchaseRecordMapper.getInvoicingAmount(anyLong())).thenReturn(amount);
BigDecimal invoicingAmount = purchaseService.getInvoicingAmount(1l);
assertEquals(recordDO.getTotalAmount(), invoicingAmount);
assertEquals(invoicingAmount, amount);
}
@Test
@@ -337,34 +371,20 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
organId, Collections.singletonList(reqVO)
);
// 查询数据库验证
List<PurchaseRecordDO> records = purchaseRecordMapper.selectList(
new LambdaQueryWrapper<PurchaseRecordDO>()
.eq(PurchaseRecordDO::getOrganId, organId)
.eq(PurchaseRecordDO::getProductId, productId)
);
assertEquals(1, records.size());
PurchaseRecordDO record = records.get(0);
// 断言核心字段
assertTrue(record.getId() > 0);
assertEquals("测试产品", record.getProductName());
assertEquals(price, record.getTotalAmount());
assertEquals(price, record.getOriginalAmount());
// monthAverageAmount = price / 10
assertEquals(new BigDecimal("100.00"), record.getMonthAverageAmount());
// 初始化语义
assertTrue(record.getInitial());
assertEquals(1, record.getPurchaseDuration());
assertEquals(ProductDurationUnitEnum.YEAR.getCode(), record.getPurchaseDurationUnit());
assertEquals(PurchaseRecordStatusEnum.ACTIVE.getStatus(), record.getStatus());
// 过期时间
assertEquals(LocalDate.now().minusDays(1), record.getEndTime());
// 校验插入
verify(purchaseRecordMapper).insert(argThat((PurchaseRecordDO purchaseRecordDO) ->
purchaseRecordDO.getProductName().equals(productsDO.getProductName())
&& purchaseRecordDO.getProductId().equals(productsDO.getId())
&& purchaseRecordDO.getPurchaseDuration().equals(1)
&& purchaseRecordDO.getPurchaseDurationUnit().equals(ProductDurationUnitEnum.YEAR.getCode())
&& purchaseRecordDO.getProductDetailsId() == 0
&& purchaseRecordDO.getStatus().equals(PurchaseRecordStatusEnum.ACTIVE.getStatus())
&& purchaseRecordDO.getInitial().equals(true)
&& purchaseRecordDO.getMonthAverageAmount().equals(new BigDecimal("100.00"))
&& purchaseRecordDO.getTotalAmount().equals(price)
&& purchaseRecordDO.getOriginalAmount().equals(price)
&& purchaseRecordDO.getEndTime().equals(LocalDate.now().minusDays(1))
));
}
@Test
@@ -384,7 +404,7 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
Long organId = 1L;
// DB 中已有首购记录
PurchaseRecordDO record = randomPojo(PurchaseRecordDO.class, o -> {
PurchaseRecordDO recordDO = randomPojo(PurchaseRecordDO.class, o -> {
o.setCreateTime(LocalDateTime.now());
o.setExternalSpent(new BigDecimal("100.00"));
o.setProductName("测试产品");
@@ -395,20 +415,16 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
o.setInitial(false);
o.setOrganId(organId);
});
purchaseRecordMapper.insert(record);
purchaseRecordMapper.insert(recordDO);
// 入参:updateList 中的 purchaseId 不存在
OrganCreateProductPurchaseReqVO reqVO = new OrganCreateProductPurchaseReqVO();
reqVO.setPurchaseId(9999L);
reqVO.setPrice(new BigDecimal("1000"));
ServiceException ex = assertThrows(ServiceException.class, () ->
purchaseService.updateOrgInitProductPurchaseRecord(
organId, Collections.singletonList(reqVO)
)
);
assertEquals(ORG_PRODUCT_PURCHASE_NOT_EXIST_ERROR.getCode(), ex.getCode());
assertServiceException(() -> purchaseService.updateOrgInitProductPurchaseRecord(
organId, Collections.singletonList(reqVO)
), ORG_PRODUCT_PURCHASE_NOT_EXIST_ERROR);
}
@Test
@@ -417,7 +433,7 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
Long productId = 10L;
// DB 中已有首购记录
PurchaseRecordDO record = randomPojo(PurchaseRecordDO.class, o -> {
PurchaseRecordDO recordDO = randomPojo(PurchaseRecordDO.class, o -> {
o.setCreateTime(LocalDateTime.now());
o.setExternalSpent(new BigDecimal("100.00"));
o.setProductName("测试产品");
@@ -429,20 +445,16 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
o.setOrganId(organId);
o.setProductId(productId);
});
purchaseRecordMapper.insert(record);
when(purchaseRecordMapper.selectList(any())).thenReturn(List.of(recordDO));
// 新增请求(purchaseId = null
OrganCreateProductPurchaseReqVO reqVO = new OrganCreateProductPurchaseReqVO();
reqVO.setProductId(productId);
reqVO.setPrice(new BigDecimal("500"));
ServiceException ex = assertThrows(ServiceException.class, () ->
purchaseService.updateOrgInitProductPurchaseRecord(
organId, Collections.singletonList(reqVO)
)
);
assertEquals(ORG_PRODUCT_PURCHASE_EXIST_ERROR.getCode(), ex.getCode());
assertServiceException(() -> purchaseService.updateOrgInitProductPurchaseRecord(
organId, Collections.singletonList(reqVO)
), ORG_PRODUCT_PURCHASE_EXIST_ERROR);
}
@Test
@@ -472,8 +484,7 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
o.setDeleted(false);
});
purchaseRecordMapper.insert(record1);
purchaseRecordMapper.insert(record2);
when(purchaseRecordMapper.selectList(any())).thenReturn(List.of(record1, record2));
// update 请求
OrganCreateProductPurchaseReqVO updateReq = new OrganCreateProductPurchaseReqVO();
@@ -502,20 +513,33 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
);
// 验证 update
PurchaseRecordDO updated = purchaseRecordMapper.selectById(3001L);
assertEquals(new BigDecimal("1000.00"), updated.getTotalAmount());
assertEquals(new BigDecimal("100.00"), updated.getMonthAverageAmount());
verify(purchaseRecordMapper).update(argThat((LambdaUpdateWrapper wrapper) ->
wrapper.getSqlSegment().contains("id")
&& wrapper.getSqlSegment().contains("organ_id")
&& wrapper.getSqlSegment().contains("initial")
&& wrapper.getSqlSet().contains("total_amount")
&& wrapper.getSqlSet().contains("month_average_amount")
&& wrapper.getSqlSet().contains("original_amount")
));
// 验证 delete3002 被删)
assertNull(purchaseRecordMapper.selectById(3002L));
verify(purchaseRecordMapper, times(1)).deleteByIds(List.of(record2.getId()));
// 验证 create
List<PurchaseRecordDO> list = purchaseRecordMapper.selectList(
new LambdaQueryWrapper<PurchaseRecordDO>()
.eq(PurchaseRecordDO::getOrganId, organId)
.eq(PurchaseRecordDO::getProductId, 103L)
);
assertEquals(1, list.size());
// 校验插入
verify(purchaseRecordMapper).insert(argThat((PurchaseRecordDO purchaseRecordDO) ->
purchaseRecordDO.getProductName().equals(productsDO.getProductName())
&& purchaseRecordDO.getProductId().equals(productsDO.getId())
&& purchaseRecordDO.getPurchaseDuration().equals(1)
&& purchaseRecordDO.getPurchaseDurationUnit().equals(ProductDurationUnitEnum.YEAR.getCode())
&& purchaseRecordDO.getProductDetailsId() == 0
&& purchaseRecordDO.getStatus().equals(PurchaseRecordStatusEnum.ACTIVE.getStatus())
&& purchaseRecordDO.getInitial().equals(true)
&& purchaseRecordDO.getMonthAverageAmount().equals(new BigDecimal("60.00"))
&& purchaseRecordDO.getTotalAmount().equals(createReq.getPrice())
&& purchaseRecordDO.getOriginalAmount().equals(createReq.getPrice())
&& purchaseRecordDO.getEndTime().equals(LocalDate.now().minusDays(1))
));
}
@Test
@@ -568,28 +592,10 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
}
@Test
public void testGetTotalSales() {
void testGetTotalSales() {
// 准备数据
PurchaseRecordDO r1 = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(2001L);
o.setDeleted(false);
o.setTotalAmount(new BigDecimal("100.00"));
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(INVOICABLE.getCode());
o.setInitial(false);
});
PurchaseRecordDO r2 = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(2002L);
o.setDeleted(false);
o.setTotalAmount(new BigDecimal("300.00"));
o.setPaymentMethod(PayChannelCodeEnum.WECHAT_NATIVE.getCode());
o.setIsInvocing(INVOICINGSUCCESSFUL.getCode());
o.setInitial(false);
});
purchaseRecordMapper.insert(r1);
purchaseRecordMapper.insert(r2);
TotalSalesAmountRespVO totalSalesAmountRespVO = new TotalSalesAmountRespVO(new BigDecimal("400.00"));
when(purchaseRecordMapper.getTotalSales()).thenReturn(totalSalesAmountRespVO);
TotalSalesAmountRespVO resp = purchaseService.getTotalSales();
@@ -598,7 +604,7 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
}
@Test
public void testGetManageSalesDetailsPage_success() {
void testGetManageSalesDetailsPage_success() {
SalesDetailsPageReqVO reqVO = new SalesDetailsPageReqVO();
Long organId = 1L;
@@ -613,7 +619,7 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
o.setInitial(false);
});
purchaseRecordMapper.insert(recordDO);
when(purchaseRecordMapper.getSaleDetailsPage(reqVO)).thenReturn(new PageResult<>(List.of(recordDO), 1L));
// mock 国际化
when(i18nUtils.getMessage(anyString())).thenReturn("支付宝");
@@ -640,7 +646,7 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
}
@Test
public void testGetManageSalesDetailsPage_organNotExist() {
void testGetManageSalesDetailsPage_organNotExist() {
SalesDetailsPageReqVO reqVO = new SalesDetailsPageReqVO();
reqVO.setPageNo(1);
reqVO.setPageSize(10);
@@ -657,7 +663,7 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
o.setInitial(false);
});
purchaseRecordMapper.insert(recordDO);
when(purchaseRecordMapper.getSaleDetailsPage(reqVO)).thenReturn(new PageResult<>(List.of(recordDO), 1L));
when(i18nUtils.getMessage(anyString())).thenReturn("微信");
when(organService.getOrganWithDeleted(organId)).thenReturn(null);
@@ -672,7 +678,7 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
}
@Test
public void testGetOrgInitialPurchaseRecord_success() {
void testGetOrgInitialPurchaseRecord_success() {
Long organId = 1L;
Long productId = 100L;
@@ -686,7 +692,7 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
o.setIsInvocing(INVOICINGSUCCESSFUL.getCode());
});
purchaseRecordMapper.insert(initialRecord);
when(purchaseRecordMapper.selectOne(any())).thenReturn(initialRecord);
PurchaseRecordDO result =
purchaseService.getOrgInitialPurchaseRecord(organId, productId);
@@ -697,7 +703,7 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
}
@Test
public void testGetOrgProductPendingPurchaseList_success() {
void testGetOrgProductPendingPurchaseList_success() {
Long organId = 3L;
Long productId = 300L;
@@ -711,18 +717,7 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
o.setIsInvocing(INVOICINGSUCCESSFUL.getCode());
});
// 干扰数据
PurchaseRecordDO active = randomPojo(PurchaseRecordDO.class, o -> {
o.setOrganId(organId);
o.setProductId(productId);
o.setStatus(PurchaseRecordStatusEnum.ACTIVE.getStatus());
o.setDeleted(false);
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(INVOICINGSUCCESSFUL.getCode());
});
purchaseRecordMapper.insert(pending1);
purchaseRecordMapper.insert(active);
when(purchaseRecordMapper.selectList(any())).thenReturn(List.of(pending1));
List<PurchaseRecordDO> result =
purchaseService.getOrgProductPendingPurchaseList(organId, productId);
@@ -734,14 +729,14 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
@Test
void test_noInitialPurchase_withYearPricing_noPromotion() {
Long PRODUCT_ID = 100L;
Long ORGAN_ID = 1L;
Long productId = 100L;
Long organId = 1L;
ProductsDO product = new ProductsDO();
product.setId(PRODUCT_ID);
product.setId(productId);
product.setPrice(new BigDecimal("1200"));
when(productsDetailService.validateProductExist(PRODUCT_ID))
when(productsDetailService.validateProductExist(productId))
.thenReturn(product);
ProductsDetailDO yearDetail = new ProductsDetailDO();
@@ -752,11 +747,11 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
when(productsDetailService.getPage(any()))
.thenReturn(new PageResult<>(List.of(yearDetail), 1L));
when(productPromotionService.getAvailableProductPromotionList(PRODUCT_ID))
when(productPromotionService.getAvailableProductPromotionList(productId))
.thenReturn(Collections.emptyList());
List<ProductDetailsRespVO> result =
purchaseService.getOrgProductDetailList(ORGAN_ID, PRODUCT_ID);
purchaseService.getOrgProductDetailList(organId, productId);
// 10个月 + 1年
assertEquals(11, result.size());
@@ -773,14 +768,14 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
@Test
void test_withInitialPurchase_withYearPricing_withPromotion() {
Long PRODUCT_ID = 100L;
Long ORGAN_ID = 1L;
Long productId = 100L;
Long organId = 1L;
ProductsDO product = new ProductsDO();
product.setId(PRODUCT_ID);
product.setId(productId);
product.setPrice(new BigDecimal("999"));
when(productsDetailService.validateProductExist(PRODUCT_ID))
when(productsDetailService.validateProductExist(productId))
.thenReturn(product);
ProductsDetailDO yearDetail = new ProductsDetailDO();
@@ -797,15 +792,15 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
promotion.setGiftDuration(3);
promotion.setGiftDurationUnit(ProductDurationUnitEnum.MONTH.getCode());
when(productPromotionService.getAvailableProductPromotionList(PRODUCT_ID))
when(productPromotionService.getAvailableProductPromotionList(productId))
.thenReturn(List.of(promotion));
PurchaseRecordDO record = new PurchaseRecordDO();
record.setTotalAmount(new BigDecimal("1000"));
record.setMonthAverageAmount(new BigDecimal("100"));
PurchaseRecordDO recordDO = new PurchaseRecordDO();
recordDO.setTotalAmount(new BigDecimal("1000"));
recordDO.setMonthAverageAmount(new BigDecimal("100"));
ProductDetailsRespVO year =
purchaseService.getOrgProductDetailList(ORGAN_ID, PRODUCT_ID)
purchaseService.getOrgProductDetailList(organId, productId)
.stream()
.filter(r -> r.getDurationUnit().equals(ProductDurationUnitEnum.YEAR.getCode()))
.findFirst().orElseThrow();
@@ -821,14 +816,14 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
@Test
void test_withInitialPurchase_withoutYearPricing_autoFillYear() {
Long PRODUCT_ID = 100L;
Long ORGAN_ID = 1L;
Long productId = 100L;
Long organId = 1L;
ProductsDO product = new ProductsDO();
product.setId(PRODUCT_ID);
product.setId(productId);
product.setPrice(new BigDecimal("888"));
when(productsDetailService.validateProductExist(PRODUCT_ID))
when(productsDetailService.validateProductExist(productId))
.thenReturn(product);
// 只有 MONTH
@@ -839,15 +834,15 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
when(productsDetailService.getPage(any()))
.thenReturn(new PageResult<>(List.of(monthDetail), 1L));
when(productPromotionService.getAvailableProductPromotionList(PRODUCT_ID))
when(productPromotionService.getAvailableProductPromotionList(productId))
.thenReturn(Collections.emptyList());
PurchaseRecordDO record = new PurchaseRecordDO();
record.setTotalAmount(new BigDecimal("888"));
record.setMonthAverageAmount(new BigDecimal("88.8"));
PurchaseRecordDO recordDO = new PurchaseRecordDO();
recordDO.setTotalAmount(new BigDecimal("888"));
recordDO.setMonthAverageAmount(new BigDecimal("88.8"));
List<ProductDetailsRespVO> result =
purchaseService.getOrgProductDetailList(ORGAN_ID, PRODUCT_ID);
purchaseService.getOrgProductDetailList(organId, productId);
ProductDetailsRespVO year =
result.stream()
@@ -860,20 +855,20 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
@Test
void test_getInitialProductProductPriceNullError(){
Long PRODUCT_ID = 100L;
Long ORGAN_ID = 1L;
Long productId = 100L;
Long organId = 1L;
ProductsDO product = new ProductsDO();
product.setId(PRODUCT_ID);
product.setId(productId);
when(productsDetailService.validateProductExist(PRODUCT_ID))
when(productsDetailService.validateProductExist(productId))
.thenReturn(product);
when(productsDetailService.getPage(any()))
.thenReturn(new PageResult<>(anyList(), 1L));
ServiceException ex = assertThrows(ServiceException.class, () ->
purchaseService.getOrgProductDetailList(ORGAN_ID, PRODUCT_ID)
purchaseService.getOrgProductDetailList(organId, productId)
);
assertEquals(PRODUCT_PRICE_NULL_ERROR.getCode(), ex.getCode());
@@ -881,14 +876,14 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
@Test
void test_getOrgProductDetailList_WithOrgInitial() {
Long PRODUCT_ID = 100L;
Long ORGAN_ID = 1L;
Long productId = 100L;
Long organId = 1L;
ProductsDO product = new ProductsDO();
product.setId(PRODUCT_ID);
product.setId(productId);
product.setPrice(new BigDecimal("1000"));
when(productsDetailService.validateProductExist(PRODUCT_ID))
when(productsDetailService.validateProductExist(productId))
.thenReturn(product);
ProductsDetailDO yearDetail = new ProductsDetailDO();
@@ -902,13 +897,13 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
productPromotionDO.setPurchaseDuration(2);
productPromotionDO.setPurchaseDurationUnit(ProductDurationUnitEnum.YEAR.getCode());
// 优惠活动
when(productPromotionService.getAvailableProductPromotionList(PRODUCT_ID))
when(productPromotionService.getAvailableProductPromotionList(productId))
.thenReturn(Collections.singletonList(productPromotionDO));
// 插入首购记录
PurchaseRecordDO recordDO = randomPojo(PurchaseRecordDO.class, o -> {
o.setOrganId(ORGAN_ID);
o.setProductId(PRODUCT_ID);
o.setOrganId(organId);
o.setProductId(productId);
o.setStatus(PurchaseRecordStatusEnum.PENDING.getStatus());
o.setDeleted(false);
o.setPaymentMethod(PayChannelCodeEnum.WECHAT_NATIVE.getCode());
@@ -917,10 +912,10 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
o.setMonthAverageAmount(new BigDecimal("99"));
o.setTotalAmount(new BigDecimal("999"));
});
purchaseRecordMapper.insert(recordDO);
when(purchaseRecordMapper.selectOne(any())).thenReturn(recordDO);
List<ProductDetailsRespVO> result =
purchaseService.getOrgProductDetailList(ORGAN_ID, PRODUCT_ID);
purchaseService.getOrgProductDetailList(organId, productId);
ProductDetailsRespVO year =
result.stream()
@@ -928,71 +923,19 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
.findFirst().orElseThrow();
assertEquals(new BigDecimal("1198.80"), year.getCurrentPrice());
assertEquals(new BigDecimal("1998.00"), year.getOriginalPrice());
}
@Test
void test_getOrgProductDetailList_WithYear() {
Long PRODUCT_ID = 100L;
Long ORGAN_ID = 1L;
ProductsDO product = new ProductsDO();
product.setId(PRODUCT_ID);
product.setPrice(new BigDecimal("1000"));
when(productsDetailService.validateProductExist(PRODUCT_ID))
.thenReturn(product);
ProductsDetailDO yearDetail = new ProductsDetailDO();
yearDetail.setDuration(2);
yearDetail.setDurationUnit(ProductDurationUnitEnum.YEAR.getCode());
yearDetail.setDiscount(new BigDecimal("60"));
when(productsDetailService.getPage(any()))
.thenReturn(new PageResult<>(List.of(yearDetail), 1L));
ProductPromotionDO productPromotionDO = new ProductPromotionDO();
productPromotionDO.setPurchaseDuration(2);
productPromotionDO.setPurchaseDurationUnit(ProductDurationUnitEnum.YEAR.getCode());
// 优惠活动
when(productPromotionService.getAvailableProductPromotionList(PRODUCT_ID))
.thenReturn(Collections.singletonList(productPromotionDO));
// 插入首购记录
PurchaseRecordDO recordDO = randomPojo(PurchaseRecordDO.class, o -> {
o.setOrganId(ORGAN_ID);
o.setProductId(PRODUCT_ID);
o.setStatus(PurchaseRecordStatusEnum.PENDING.getStatus());
o.setDeleted(false);
o.setPaymentMethod(PayChannelCodeEnum.WECHAT_NATIVE.getCode());
o.setIsInvocing(INVOICINGSUCCESSFUL.getCode());
o.setInitial(true);
o.setMonthAverageAmount(new BigDecimal("99"));
o.setTotalAmount(new BigDecimal("999"));
});
purchaseRecordMapper.insert(recordDO);
List<ProductDetailsRespVO> result =
purchaseService.getOrgProductDetailList(ORGAN_ID, PRODUCT_ID);
ProductDetailsRespVO year =
result.stream()
.filter(r -> r.getDurationUnit().equals(ProductDurationUnitEnum.YEAR.getCode()))
.findFirst().orElseThrow();
assertEquals(new BigDecimal("1198.80"), year.getCurrentPrice());
assertEquals(new BigDecimal("1998.00"), year.getOriginalPrice());
assertEquals(new BigDecimal("1998"), year.getOriginalPrice());
}
@Test
void test_getOrgProductDetailList_WithoutYear() {
Long PRODUCT_ID = 100L;
Long ORGAN_ID = 1L;
Long productId = 100L;
Long organId = 1L;
ProductsDO product = new ProductsDO();
product.setId(PRODUCT_ID);
product.setId(productId);
product.setPrice(new BigDecimal("1000"));
when(productsDetailService.validateProductExist(PRODUCT_ID))
when(productsDetailService.validateProductExist(productId))
.thenReturn(product);
ProductsDetailDO monthDetail = new ProductsDetailDO();
@@ -1005,13 +948,13 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
productPromotionDO.setPurchaseDuration(2);
productPromotionDO.setPurchaseDurationUnit(ProductDurationUnitEnum.YEAR.getCode());
// 优惠活动
when(productPromotionService.getAvailableProductPromotionList(PRODUCT_ID))
when(productPromotionService.getAvailableProductPromotionList(productId))
.thenReturn(Collections.singletonList(productPromotionDO));
// 插入首购记录
PurchaseRecordDO recordDO = randomPojo(PurchaseRecordDO.class, o -> {
o.setOrganId(ORGAN_ID);
o.setProductId(PRODUCT_ID);
o.setOrganId(organId);
o.setProductId(productId);
o.setStatus(PurchaseRecordStatusEnum.PENDING.getStatus());
o.setDeleted(false);
o.setPaymentMethod(PayChannelCodeEnum.WECHAT_NATIVE.getCode());
@@ -1020,10 +963,10 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
o.setMonthAverageAmount(new BigDecimal("99"));
o.setTotalAmount(new BigDecimal("999"));
});
purchaseRecordMapper.insert(recordDO);
when(purchaseRecordMapper.selectOne(any())).thenReturn(recordDO);
List<ProductDetailsRespVO> result =
purchaseService.getOrgProductDetailList(ORGAN_ID, PRODUCT_ID);
purchaseService.getOrgProductDetailList(organId, productId);
ProductDetailsRespVO year =
result.stream()
@@ -1040,26 +983,16 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
Long organId = 1L;
Long recordId = 101L;
PurchaseRecordDO recordDO = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(recordId);
o.setOrganId(organId);
o.setStatus(PurchaseRecordStatusEnum.PENDING.getStatus());
o.setDeleted(false);
o.setPaymentMethod(PayChannelCodeEnum.WECHAT_NATIVE.getCode());
o.setIsInvocing(INVOICINGSUCCESSFUL.getCode());
o.setInitial(true);
o.setMonthAverageAmount(new BigDecimal("99"));
o.setTotalAmount(new BigDecimal("999"));
});
purchaseRecordMapper.insert(recordDO);
purchaseService.invalidHistoryOrganProductPurchaseRecord(organId, recordId);
PurchaseRecordDO updated =
purchaseRecordMapper.selectById(recordId);
assertEquals(PurchaseRecordStatusEnum.INACTIVE.getStatus(), updated.getStatus());
// 校验状态更新
verify(purchaseRecordMapper).update(argThat((LambdaUpdateWrapper wrapper) ->
wrapper.getSqlSegment().contains("organ_id")
&& wrapper.getSqlSegment().contains("id")
&& wrapper.getSqlSegment().contains("deleted")
&& wrapper.getSqlSegment().contains("status")
&& wrapper.getSqlSet().contains("status")
));
}
@Test
@@ -1067,60 +1000,25 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
Long organId = 1L;
Long recordId = 200L;
PurchaseRecordDO record = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(recordId);
o.setOrganId(organId);
o.setStatus(PurchaseRecordStatusEnum.PENDING.getStatus());
o.setDeleted(false);
o.setPaymentMethod(PayChannelCodeEnum.WECHAT_NATIVE.getCode());
o.setIsInvocing(INVOICINGSUCCESSFUL.getCode());
o.setInitial(true);
o.setMonthAverageAmount(new BigDecimal("99"));
o.setTotalAmount(new BigDecimal("999"));
});
purchaseRecordMapper.insert(record);
// when
purchaseService.activateHistoryOrganProductPurchaseRecord(organId, recordId);
// then
PurchaseRecordDO updated = purchaseRecordMapper.selectById(recordId);
assertEquals(
PurchaseRecordStatusEnum.ACTIVE.getStatus(),
updated.getStatus()
);
// 校验状态更新
verify(purchaseRecordMapper).update(argThat((LambdaUpdateWrapper wrapper) ->
wrapper.getSqlSegment().contains("organ_id")
&& wrapper.getSqlSegment().contains("id")
&& wrapper.getSqlSegment().contains("deleted")
&& wrapper.getSqlSegment().contains("status")
&& wrapper.getSqlSet().contains("status")
));
}
@Test
void should_return_correct_sales_statistics() {
Long organId = 1L;
PurchaseRecordDO record1 = randomPojo(PurchaseRecordDO.class, o -> {
o.setOrganId(organId);
o.setStatus(PurchaseRecordStatusEnum.PENDING.getStatus());
o.setDeleted(false);
o.setPaymentMethod(PayChannelCodeEnum.WECHAT_NATIVE.getCode());
o.setIsInvocing(INVOICINGSUCCESSFUL.getCode());
o.setInitial(false);
o.setMonthAverageAmount(new BigDecimal("99"));
o.setTotalAmount(new BigDecimal("200"));
o.setCreateTime(LocalDateTime.now().minusDays(2));
});
PurchaseRecordDO record2 = randomPojo(PurchaseRecordDO.class, o -> {
o.setOrganId(organId);
o.setStatus(PurchaseRecordStatusEnum.PENDING.getStatus());
o.setDeleted(false);
o.setPaymentMethod(PayChannelCodeEnum.WECHAT_NATIVE.getCode());
o.setIsInvocing(INVOICINGSUCCESSFUL.getCode());
o.setInitial(false);
o.setTotalAmount(new BigDecimal("100"));
o.setCreateTime(LocalDateTime.now());
});
purchaseRecordMapper.insert(record1);
purchaseRecordMapper.insert(record2);
TotalSalesAmountRespVO totalSalesAmountRespVO = new TotalSalesAmountRespVO(new BigDecimal(300));
when(purchaseRecordMapper.getTotalSales()).thenReturn(totalSalesAmountRespVO);
when(purchaseRecordMapper.getTodaySales(any())).thenReturn(new BigDecimal(100));
// when
ManageSalesTotalStatisticRespVO resp =
@@ -1128,8 +1026,8 @@ class PurchaseServiceImplTest extends BaseDbAndRedisUnitTest {
// then
assertAll(
() -> assertEquals(new BigDecimal("300.00"), resp.getSalesTotal()),
() -> assertEquals(new BigDecimal("100.00"), resp.getSalesToday())
() -> assertEquals(new BigDecimal("300"), resp.getSalesTotal()),
() -> assertEquals(new BigDecimal("100"), resp.getSalesToday())
);
}
}
@@ -1,28 +1,23 @@
package com.cf.imes.module.system.service.funds.statistics;
import com.cf.imes.framework.common.enums.StatisticsUnit;
import com.cf.imes.framework.common.util.i18n.core.util.I18nUtils;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.framework.security.test.WithMockLoginUser;
import com.cf.imes.framework.test.core.ut.BaseDbAndRedisUnitTest;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganFundsStatisticsReqVO;
import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest;
import com.cf.imes.module.system.controller.admin.statistics.vo.OrgStatusGroupStatisticsReqVO;
import com.cf.imes.module.system.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO;
import com.cf.imes.module.system.dal.dataobject.funds.statistics.FundsTradeTypeGroupStatisticsDO;
import com.cf.imes.module.system.dal.mysql.incomeandexpense.IncomeExpenseDetailsMapper;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static com.cf.imes.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
/**
*
@@ -30,23 +25,16 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
* @author Gqr
* @since 2025/12/31 15:20
*/
@Import(FundsStatisticsServiceImpl.class)
public class FundsStatisticsServiceImplTest extends BaseDbAndRedisUnitTest {
class FundsStatisticsServiceImplTest extends BaseMockitoUnitTest {
@Resource
@InjectMocks
private FundsStatisticsServiceImpl fundsStatisticsService;
@MockitoBean
private I18nUtils i18nUtils;
@Resource
@Mock
private IncomeExpenseDetailsMapper incomeExpenseDetailsMapper;
@Test
@WithMockLoginUser(organId = 1L)
void should_return_consumption_trend_with_zero_filling() {
Long organId = SecurityFrameworkUtils.getUserOrganId();
OrgStatusGroupStatisticsReqVO reqVO = new OrgStatusGroupStatisticsReqVO();
reqVO.setUnit(StatisticsUnit.DAY.getValue());
reqVO.setCreateTime(new LocalDate[]{
@@ -54,24 +42,10 @@ public class FundsStatisticsServiceImplTest extends BaseDbAndRedisUnitTest {
LocalDate.now().plusDays(1)
});
IncomeExpenseDetailsDO pojo1 = randomPojo(IncomeExpenseDetailsDO.class, o -> {
o.setOrganId(organId);
o.setAmount(new BigDecimal("100"));
o.setCreateTime(LocalDateTime.now().minusDays(2));
});
IncomeExpenseDetailsDO pojo2 = randomPojo(IncomeExpenseDetailsDO.class, o -> {
o.setOrganId(organId);
o.setAmount(new BigDecimal("200"));
o.setCreateTime(LocalDateTime.now());
});
IncomeExpenseDetailsDO pojo3 = randomPojo(IncomeExpenseDetailsDO.class, o -> {
o.setAmount(new BigDecimal("200"));
o.setCreateTime(LocalDateTime.now());
});
incomeExpenseDetailsMapper.insert(pojo1);
incomeExpenseDetailsMapper.insert(pojo2);
incomeExpenseDetailsMapper.insert(pojo3);
List<FundsTradeTypeGroupStatisticsDO> purchaseList = new ArrayList<>();
purchaseList.add(new FundsTradeTypeGroupStatisticsDO(new BigDecimal("100"), "2026-1-18"));
purchaseList.add(new FundsTradeTypeGroupStatisticsDO(new BigDecimal("400"), "2026-1-20"));
when(incomeExpenseDetailsMapper.selectTotalSalesTrendGroupByCreateTime(reqVO)).thenReturn(purchaseList);
// when query
Map<String, Object> result =
@@ -88,9 +62,9 @@ public class FundsStatisticsServiceImplTest extends BaseDbAndRedisUnitTest {
assertArrayEquals(
new BigDecimal[]{
new BigDecimal("100.00"),
new BigDecimal("100"),
BigDecimal.ZERO,
new BigDecimal("400.00"),
new BigDecimal("400"),
BigDecimal.ZERO,
},
data