package com.ruoyi.other.service.impl; import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import com.ruoyi.other.api.domain.TGroupCompany; import com.ruoyi.other.api.model.TCompanyRechargeRecord; import com.ruoyi.other.mapper.TCompanyRechargeRecordMapper; import com.ruoyi.other.mapper.TFleetMapper; import org.apache.ibatis.builder.MapperBuilderAssistant; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.springframework.test.util.ReflectionTestUtils; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; /** * 公司详情(车队数量、本月充值金额)统计逻辑单测,不依赖 Spring 容器与数据库。 */ class TGroupCompanyServiceImplTest { @BeforeAll static void initTableInfo() { // 初始化 MyBatis-Plus 表元数据,使 LambdaQueryWrapper 可在无 Spring/DB 环境下解析列名 TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), TCompanyRechargeRecord.class); } @Test void fillsFleetCountAndCurrentMonthRechargeAmount() { TGroupCompany company = new TGroupCompany(); company.setId(1); TFleetMapper fleetMapper = Mockito.mock(TFleetMapper.class); Mockito.when(fleetMapper.selectCount(Mockito.any())).thenReturn(3L); TCompanyRechargeRecordMapper rechargeMapper = Mockito.mock(TCompanyRechargeRecordMapper.class); Mockito.when(rechargeMapper.selectList(Mockito.any())) .thenReturn(Arrays.asList(record("100.00"), record(null), record("50.50"))); TGroupCompany detail = buildService(company, fleetMapper, rechargeMapper).getDetail(1); assertEquals(3, detail.getFleetCount()); assertEquals(new BigDecimal("150.50"), detail.getMonthRechargeAmount()); } @Test void returnsZeroAmountWhenNoRechargeRecordInCurrentMonth() { TGroupCompany company = new TGroupCompany(); company.setId(1); TFleetMapper fleetMapper = Mockito.mock(TFleetMapper.class); Mockito.when(fleetMapper.selectCount(Mockito.any())).thenReturn(null); TCompanyRechargeRecordMapper rechargeMapper = Mockito.mock(TCompanyRechargeRecordMapper.class); Mockito.when(rechargeMapper.selectList(Mockito.any())).thenReturn(Collections.emptyList()); TGroupCompany detail = buildService(company, fleetMapper, rechargeMapper).getDetail(1); assertEquals(0, detail.getFleetCount()); assertEquals(0, new BigDecimal("0.00").compareTo(detail.getMonthRechargeAmount())); assertEquals(2, detail.getMonthRechargeAmount().scale()); } @Test void returnsNullAndSkipsStatisticsWhenCompanyNotExists() { TFleetMapper fleetMapper = Mockito.mock(TFleetMapper.class); TCompanyRechargeRecordMapper rechargeMapper = Mockito.mock(TCompanyRechargeRecordMapper.class); TGroupCompany detail = buildService(null, fleetMapper, rechargeMapper).getDetail(9); assertNull(detail); Mockito.verifyNoInteractions(fleetMapper, rechargeMapper); } @Test @SuppressWarnings("unchecked") void queriesCurrentMonthRechargeRecordsByCompanyAndTimeRange() { TGroupCompany company = new TGroupCompany(); company.setId(2); TFleetMapper fleetMapper = Mockito.mock(TFleetMapper.class); Mockito.when(fleetMapper.selectCount(Mockito.any())).thenReturn(0L); TCompanyRechargeRecordMapper rechargeMapper = Mockito.mock(TCompanyRechargeRecordMapper.class); Mockito.when(rechargeMapper.selectList(Mockito.any())).thenReturn(Collections.emptyList()); buildService(company, fleetMapper, rechargeMapper).getDetail(2); ArgumentCaptor> captor = ArgumentCaptor.forClass(Wrapper.class); // getDetail 会查询两次充值记录:本月 + 累计;首次调用为本月查询 Mockito.verify(rechargeMapper, Mockito.times(2)).selectList(captor.capture()); // 过滤条件:company_id = 2,且 recharge_time ∈ [本月1日 00:00:00, 次月1日 00:00:00) String sqlSegment = captor.getAllValues().get(0).getSqlSegment(); assertTrue(sqlSegment.contains("company_id"), sqlSegment); assertTrue(sqlSegment.contains("recharge_time"), sqlSegment); LocalDateTime start = TGroupCompanyServiceImpl.monthStart(LocalDate.now()); Map paramValues = (Map) ReflectionTestUtils.getField(captor.getAllValues().get(0), "paramNameValuePairs"); assertTrue(paramValues != null && paramValues.containsValue(2), String.valueOf(paramValues)); assertTrue(paramValues != null && paramValues.containsValue(start), String.valueOf(paramValues)); assertTrue(paramValues != null && paramValues.containsValue(start.plusMonths(1)), String.valueOf(paramValues)); } @Test void monthStartIsTheFirstDayOfNaturalMonth() { assertEquals(LocalDateTime.of(2026, 9, 1, 0, 0, 0), TGroupCompanyServiceImpl.monthStart(LocalDate.of(2026, 9, 24))); assertEquals(LocalDateTime.of(2026, 9, 1, 0, 0, 0), TGroupCompanyServiceImpl.monthStart(LocalDate.of(2026, 9, 1))); assertEquals(LocalDateTime.of(2027, 1, 1, 0, 0, 0), TGroupCompanyServiceImpl.monthStart(LocalDate.of(2026, 12, 31)).plusMonths(1)); } @Test void sumArrivalAmountReturnsZeroWithScaleForEmptyList() { assertEquals(new BigDecimal("0.00"), TGroupCompanyServiceImpl.sumArrivalAmount(new ArrayList<>())); } private TGroupCompanyServiceImpl buildService(TGroupCompany company, TFleetMapper fleetMapper, TCompanyRechargeRecordMapper rechargeMapper) { TGroupCompanyServiceImpl service = Mockito.spy(new TGroupCompanyServiceImpl()); Mockito.doReturn(company).when(service).getById(Mockito.any()); ReflectionTestUtils.setField(service, "fleetMapper", fleetMapper); ReflectionTestUtils.setField(service, "companyRechargeRecordMapper", rechargeMapper); return service; } private TCompanyRechargeRecord record(String arrivalAmount) { TCompanyRechargeRecord record = new TCompanyRechargeRecord(); record.setArrivalAmount(arrivalAmount == null ? null : new BigDecimal(arrivalAmount)); return record; } }