package com.ruoyi.order.service.impl; import com.ruoyi.account.api.feignClient.AppUserIntegralChangeClient; import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient; import com.ruoyi.chargingPile.api.feignClient.ChargingPileClient; import com.ruoyi.chargingPile.api.feignClient.SiteClient; import com.ruoyi.chargingPile.api.model.Site; import com.ruoyi.chargingPile.api.model.TChargingGun; import com.ruoyi.chargingPile.api.model.TChargingPile; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.integration.api.model.UploadRealTimeMonitoringData; import com.ruoyi.order.api.model.TChargingOrder; import com.ruoyi.order.api.model.TVinChargingOrder; import com.ruoyi.order.dto.ChargingDetails; import com.ruoyi.order.mapper.TChargingOrderMapper; import com.ruoyi.order.mapper.TVinChargingOrderMapper; import com.ruoyi.order.util.mongodb.service.UploadRealTimeMonitoringDataService; import com.ruoyi.order.vo.EndOfChargePageInfo; import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import com.ruoyi.system.api.model.LoginUserApplet; import org.apache.ibatis.builder.MapperBuilderAssistant; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.util.ReflectionTestUtils; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.Arrays; import java.util.Collections; 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.Mockito.when; /** * TChargingOrderServiceImpl 小程序接口对 VIN 码充电订单(t_vin_charging_order)的兜底逻辑测试: * getChargingDetails(正在充电详情)、getEndOfChargePageInfo(结束页详情)。 */ @ExtendWith(MockitoExtension.class) class TChargingOrderServiceImplVinFallbackTest { @InjectMocks private TChargingOrderServiceImpl service; @Mock private TChargingOrderMapper mapper; @Mock private TVinChargingOrderMapper vinChargingOrderMapper; @Mock private TokenService tokenService; @Mock private ChargingGunClient chargingGunClient; @Mock private ChargingPileClient chargingPileClient; @Mock private SiteClient siteClient; @Mock private UploadRealTimeMonitoringDataService uploadRealTimeMonitoringDataService; @Mock private AppUserIntegralChangeClient appUserIntegralChangeClient; /** * 纯单测无 Spring 容器,MyBatis-Plus 的 lambda 列缓存需手工初始化, * 否则 LambdaQueryWrapper 解析 getter 引用时抛 "can not find lambda cache" */ @BeforeAll static void initMybatisPlusTableInfo() { MapperBuilderAssistant assistant = new MapperBuilderAssistant(new MybatisConfiguration(), ""); TableInfoHelper.initTableInfo(assistant, TChargingOrder.class); TableInfoHelper.initTableInfo(assistant, TVinChargingOrder.class); } @BeforeEach void setUp() { ReflectionTestUtils.setField(service, "baseMapper", mapper); } @Test void getChargingDetailsFallsBackToVinOrderAndAssemblesRealTimeData() { LoginUserApplet loginUser = new LoginUserApplet(); loginUser.setUserId(88L); when(tokenService.getLoginUserApplet()).thenReturn(loginUser); // 普通订单表查不到 when(mapper.selectOne(any())).thenReturn(null); TVinChargingOrder vinOrder = new TVinChargingOrder(); vinOrder.setId(1001L); vinOrder.setAppUserId(88L); vinOrder.setChargingGunId(5); vinOrder.setStatus(3); vinOrder.setCode("VD20261013001"); vinOrder.setResidualAmount(new BigDecimal("66.60")); when(vinChargingOrderMapper.selectOne(any())).thenReturn(vinOrder); TChargingGun gun = new TChargingGun(); gun.setChargingPileId(7); when(chargingGunClient.getChargingGunById(5)).thenReturn(R.ok(gun)); TChargingPile pile = new TChargingPile(); pile.setName("1号桩"); pile.setSiteId(9); when(chargingPileClient.getChargingPileById(7)).thenReturn(R.ok(pile)); Site site = new Site(); site.setName("城东站"); when(siteClient.getSiteByIds(Arrays.asList(9))).thenReturn(R.ok(Collections.singletonList(site))); UploadRealTimeMonitoringData data = new UploadRealTimeMonitoringData(); data.setOutput_current(new BigDecimal("10")); data.setOutput_voltage(new BigDecimal("220")); data.setSoc(50); data.setTime_remaining(30); data.setCharging_degree(new BigDecimal("5.5")); data.setCumulative_charging_time(75); when(uploadRealTimeMonitoringDataService.getLastDataById("VD20261013001")).thenReturn(data); ChargingDetails details = service.getChargingDetails(5); assertEquals("1001", details.getId()); assertEquals("城东站-1号桩", details.getName()); assertEquals("VD20261013001", details.getCode()); assertEquals(Integer.valueOf(3), details.getStatus()); assertEquals(0, new BigDecimal("66.60").compareTo(details.getChargingCost())); assertEquals(0, new BigDecimal("10").compareTo(details.getChargeCurrent())); assertEquals(0, new BigDecimal("220").compareTo(details.getChargeVoltage())); assertEquals(0, new BigDecimal("2.200").compareTo(details.getChargePower())); assertEquals(Integer.valueOf(50), details.getCompletionRatio()); assertEquals(Integer.valueOf(30), details.getRemainingChargeTime()); assertEquals(0, new BigDecimal("5.5").compareTo(details.getChargedDegrees())); assertEquals("01:15", details.getChargedTime()); } @Test void getChargingDetailsReturnsNullWhenNeitherNormalNorVinOrderExists() { LoginUserApplet loginUser = new LoginUserApplet(); loginUser.setUserId(88L); when(tokenService.getLoginUserApplet()).thenReturn(loginUser); when(mapper.selectOne(any())).thenReturn(null); when(vinChargingOrderMapper.selectOne(any())).thenReturn(null); assertNull(service.getChargingDetails(5)); } @Test void getEndOfChargePageInfoFallsBackToVinOrder() { LoginUserApplet loginUser = new LoginUserApplet(); loginUser.setUserId(88L); when(tokenService.getLoginUserApplet()).thenReturn(loginUser); when(mapper.selectById("1001")).thenReturn(null); TVinChargingOrder vinOrder = new TVinChargingOrder(); vinOrder.setId(1001L); vinOrder.setAppUserId(88L); vinOrder.setCode("VD20261013001"); vinOrder.setPaymentAmount(new BigDecimal("18.50")); vinOrder.setRechargeAmount(new BigDecimal("50.00")); vinOrder.setRefundAmount(new BigDecimal("31.50")); vinOrder.setStartTime(LocalDateTime.of(2026, 10, 13, 10, 0)); vinOrder.setEndTime(LocalDateTime.of(2026, 10, 13, 11, 30)); when(vinChargingOrderMapper.selectById("1001")).thenReturn(vinOrder); when(appUserIntegralChangeClient.getTAppUserIntegralChangeByOrderCode("VD20261013001")) .thenReturn(R.ok(null)); EndOfChargePageInfo info = service.getEndOfChargePageInfo("1001"); assertEquals("1001", info.getId()); assertEquals("VD20261013001", info.getCode()); assertEquals(0, new BigDecimal("18.50").compareTo(info.getPaymentAmount())); assertEquals(0, new BigDecimal("50.00").compareTo(info.getRechargeAmount())); assertEquals(0, new BigDecimal("31.50").compareTo(info.getRefundAmount())); assertEquals(Integer.valueOf(0), info.getIntegral()); assertEquals("10:00", info.getStartHour()); assertEquals("11:30", info.getEndHour()); assertEquals("1小时30分钟", info.getDuration()); } @Test void getEndOfChargePageInfoThrowsWhenOrderMissingInBothTables() { // 两表均查不到订单时在获取登录用户之前即抛异常,tokenService 无需 stub when(mapper.selectById("1001")).thenReturn(null); when(vinChargingOrderMapper.selectById("1001")).thenReturn(null); RuntimeException exception = null; try { service.getEndOfChargePageInfo("1001"); } catch (RuntimeException ex) { exception = ex; } assertNotNull(exception); assertEquals("充电订单不存在", exception.getMessage()); } }