package com.ruoyi.order.service.impl; import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; import com.ruoyi.account.api.feignClient.ChargingCardClient; import com.ruoyi.account.api.vo.ChargingCardDeductVO; import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient; import com.ruoyi.chargingPile.api.model.TChargingGun; import com.ruoyi.common.core.domain.R; import com.ruoyi.order.api.model.TCardAccountingStrategyDetailOrder; import com.ruoyi.order.api.model.TCardChargingOrder; import com.ruoyi.order.api.model.TCardChargingOrderAccountingStrategy; import com.ruoyi.order.api.model.TVinAccountingStrategyDetailOrder; import com.ruoyi.order.api.model.TVinChargingOrder; import com.ruoyi.order.api.model.TVinChargingOrderAccountingStrategy; import com.ruoyi.order.api.vo.TransactionRecordMessageVO; import com.ruoyi.order.mapper.TCardChargingOrderMapper; import com.ruoyi.order.mapper.TVinChargingOrderMapper; import com.ruoyi.order.service.TCardAccountingStrategyDetailOrderService; import com.ruoyi.order.service.TCardChargingOrderAccountingStrategyService; import com.ruoyi.order.service.TVinAccountingStrategyDetailOrderService; import com.ruoyi.order.service.TVinChargingOrderAccountingStrategyService; import org.apache.ibatis.builder.MapperBuilderAssistant; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; 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.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; /** * SD/VD 定时补偿与结算锁行为测试(文档13.2/13.3): * 1) 启动超时关单(状态-1+结束方式0+解锁卡片+复位枪,沿用 t_charging_order 枚举约定); * 2) 结算入口并发锁抢占失败快速返回,不触达订单数据; * 3) 已结算订单重复账单幂等跳过,不再扣款/解锁; * 4) 超时补偿按排序后平段的真实序号构造 flat_chargeN。 */ class CardVinOrderCompensationTest { /** * 纯单测无 Spring 容器,MyBatis-Plus 的 lambda 列缓存需手工初始化, * 否则服务实现里的 LambdaUpdateWrapper 解析列名时抛 "can not find lambda cache" */ @BeforeAll static void initMybatisPlusTableInfo() { MapperBuilderAssistant assistant = new MapperBuilderAssistant(new MybatisConfiguration(), ""); TableInfoHelper.initTableInfo(assistant, TCardChargingOrder.class); TableInfoHelper.initTableInfo(assistant, TVinChargingOrder.class); } @SuppressWarnings("unchecked") private R okBoolean() { R result = mock(R.class); when(result.getCode()).thenReturn(R.SUCCESS); when(result.getData()).thenReturn(true); return result; } @SuppressWarnings("unchecked") private R gunOf(TChargingGun gun) { R result = mock(R.class); when(result.getCode()).thenReturn(R.SUCCESS); when(result.getData()).thenReturn(gun); return result; } private RLock mockedLock(boolean tryLockResult) throws InterruptedException { RLock lock = mock(RLock.class); when(lock.tryLock(anyLong(), anyLong(), any(TimeUnit.class))).thenReturn(tryLockResult); when(lock.isHeldByCurrentThread()).thenReturn(false); return lock; } private RedissonClient mockedRedisson(RLock lock) { RedissonClient redisson = mock(RedissonClient.class); when(redisson.getLock(anyString())).thenReturn(lock); return redisson; } // ===== SD:启动超时关单 ===== @Test void closesCardTimeoutStartingOrderWithCardUnlockAndGunReset() { TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl(); TCardChargingOrderMapper mapper = mock(TCardChargingOrderMapper.class); ChargingCardClient cardClient = mock(ChargingCardClient.class); ChargingGunClient gunClient = mock(ChargingGunClient.class); ReflectionTestUtils.setField(service, "baseMapper", mapper); ReflectionTestUtils.setField(service, "chargingCardClient", cardClient); ReflectionTestUtils.setField(service, "chargingGunClient", gunClient); when(mapper.update(any(TCardChargingOrder.class), any())).thenReturn(1); R unlockResult = okBoolean(); when(cardClient.unlockForCharging(anyLong(), anyString())).thenReturn(unlockResult); TChargingGun gun = new TChargingGun(); gun.setId(9); gun.setStatus(4); R gunResult = gunOf(gun); when(gunClient.getChargingGunById(any())).thenReturn(gunResult); TCardChargingOrder order = new TCardChargingOrder(); order.setId(1L); order.setCode("SD1"); order.setStatus(2); order.setCardId(5L); order.setChargingGunId(9); service.closeTimeoutStartingOrder(order); ArgumentCaptor captor = ArgumentCaptor.forClass(TCardChargingOrder.class); verify(mapper).update(captor.capture(), any()); assertEquals(-1, captor.getValue().getStatus()); assertEquals(0, captor.getValue().getEndMode()); assertNotNull(captor.getValue().getEndTime()); verify(cardClient).unlockForCharging(5L, "SD1"); ArgumentCaptor gunCaptor = ArgumentCaptor.forClass(TChargingGun.class); verify(gunClient).updateChargingGunById(gunCaptor.capture()); assertEquals(2, gunCaptor.getValue().getStatus()); } @Test void ignoresLateCardStartReplyAfterOrderClosed() { TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl(); TCardChargingOrderMapper mapper = mock(TCardChargingOrderMapper.class); ChargingGunClient gunClient = mock(ChargingGunClient.class); ReflectionTestUtils.setField(service, "baseMapper", mapper); ReflectionTestUtils.setField(service, "chargingGunClient", gunClient); TCardChargingOrder closed = new TCardChargingOrder(); closed.setId(1L); closed.setCode("SD1"); closed.setStatus(-1); when(mapper.selectOne(any())).thenReturn(closed); when(mapper.selectList(any())).thenReturn(Collections.singletonList(closed)); com.ruoyi.order.api.vo.PlatformStartChargingReplyMessageVO reply = new com.ruoyi.order.api.vo.PlatformStartChargingReplyMessageVO(); reply.setTransaction_serial_number("SD1"); reply.setStartup_result(1); service.cardStartChargeSuccessfully(reply); verify(mapper, never()).update(any(), any()); verifyNoInteractions(gunClient); } // ===== SD:结算锁抢占失败快速返回 ===== @Test void returnsOkWithoutTouchingOrderWhenSettleLockBusy() throws InterruptedException { TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl(); TCardChargingOrderMapper mapper = mock(TCardChargingOrderMapper.class); ReflectionTestUtils.setField(service, "baseMapper", mapper); ReflectionTestUtils.setField(service, "redissonClient", mockedRedisson(mockedLock(false))); TransactionRecordMessageVO vo = new TransactionRecordMessageVO(); vo.setTransaction_serial_number("SD1"); R result = service.cardEndChargeBillingCharge(vo); assertEquals(R.SUCCESS, result.getCode()); verifyNoInteractions(mapper); } // ===== SD:已结算订单重复账单幂等 ===== @Test void skipsCardSettlementWhenOrderAlreadyFinished() throws InterruptedException { TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl(); TCardChargingOrderMapper mapper = mock(TCardChargingOrderMapper.class); ChargingCardClient cardClient = mock(ChargingCardClient.class); ReflectionTestUtils.setField(service, "baseMapper", mapper); ReflectionTestUtils.setField(service, "chargingCardClient", cardClient); ReflectionTestUtils.setField(service, "redissonClient", mockedRedisson(mockedLock(true))); TCardChargingOrder finished = new TCardChargingOrder(); finished.setId(1L); finished.setCode("SD1"); finished.setStatus(5); finished.setCardId(5L); when(mapper.selectOne(any())).thenReturn(finished); when(mapper.selectList(any())).thenReturn(Collections.singletonList(finished)); TransactionRecordMessageVO vo = new TransactionRecordMessageVO(); vo.setTransaction_serial_number("SD1"); vo.setFlat_charge1(new java.math.BigDecimal("10")); R result = service.cardEndChargeBillingCharge(vo); assertEquals(R.SUCCESS, result.getCode()); verify(cardClient, never()).deductForCharging(any(com.ruoyi.account.api.dto.ChargingCardDeductDTO.class)); verify(cardClient, never()).unlockForCharging(anyLong(), anyString()); } // ===== VD:启动超时关单(无卡片,仅复位枪) ===== @Test void closesVinTimeoutStartingOrderWithGunReset() { TVinChargingOrderServiceImpl service = new TVinChargingOrderServiceImpl(); TVinChargingOrderMapper mapper = mock(TVinChargingOrderMapper.class); ChargingGunClient gunClient = mock(ChargingGunClient.class); ReflectionTestUtils.setField(service, "baseMapper", mapper); ReflectionTestUtils.setField(service, "chargingGunClient", gunClient); when(mapper.update(any(TVinChargingOrder.class), any())).thenReturn(1); TChargingGun gun = new TChargingGun(); gun.setId(7); gun.setStatus(4); R gunResult = gunOf(gun); when(gunClient.getChargingGunById(any())).thenReturn(gunResult); TVinChargingOrder order = new TVinChargingOrder(); order.setId(2L); order.setCode("VD1"); order.setStatus(2); order.setChargingGunId(7); service.closeTimeoutStartingOrder(order); ArgumentCaptor captor = ArgumentCaptor.forClass(TVinChargingOrder.class); verify(mapper).update(captor.capture(), any()); assertEquals(-1, captor.getValue().getStatus()); assertEquals(0, captor.getValue().getEndMode()); assertNotNull(captor.getValue().getEndTime()); ArgumentCaptor gunCaptor = ArgumentCaptor.forClass(TChargingGun.class); verify(gunClient).updateChargingGunById(gunCaptor.capture()); assertEquals(2, gunCaptor.getValue().getStatus()); } @Test void ignoresLateVinStartReplyAfterOrderClosed() { TVinChargingOrderServiceImpl service = new TVinChargingOrderServiceImpl(); TVinChargingOrderMapper mapper = mock(TVinChargingOrderMapper.class); ChargingGunClient gunClient = mock(ChargingGunClient.class); ReflectionTestUtils.setField(service, "baseMapper", mapper); ReflectionTestUtils.setField(service, "chargingGunClient", gunClient); TVinChargingOrder closed = new TVinChargingOrder(); closed.setId(2L); closed.setCode("VD1"); closed.setStatus(-1); when(mapper.selectOne(any())).thenReturn(closed); when(mapper.selectList(any())).thenReturn(Collections.singletonList(closed)); com.ruoyi.order.api.vo.PlatformStartChargingReplyMessageVO reply = new com.ruoyi.order.api.vo.PlatformStartChargingReplyMessageVO(); reply.setTransaction_serial_number("VD1"); reply.setStartup_result(1); service.vinStartChargeSuccessfully(reply); verify(mapper, never()).update(any(), any()); verifyNoInteractions(gunClient); } // ===== VD:已结算订单重复账单幂等 ===== @Test void skipsVinSettlementWhenOrderAlreadyFinished() throws InterruptedException { TVinChargingOrderServiceImpl service = new TVinChargingOrderServiceImpl(); TVinChargingOrderMapper mapper = mock(TVinChargingOrderMapper.class); ChargingGunClient gunClient = mock(ChargingGunClient.class); ReflectionTestUtils.setField(service, "baseMapper", mapper); ReflectionTestUtils.setField(service, "chargingGunClient", gunClient); ReflectionTestUtils.setField(service, "redissonClient", mockedRedisson(mockedLock(true))); TVinChargingOrder finished = new TVinChargingOrder(); finished.setId(2L); finished.setCode("VD1"); finished.setStatus(5); finished.setChargingGunId(7); when(mapper.selectOne(any())).thenReturn(finished); when(mapper.selectList(any())).thenReturn(Collections.singletonList(finished)); TransactionRecordMessageVO vo = new TransactionRecordMessageVO(); vo.setTransaction_serial_number("VD1"); vo.setFlat_charge1(new java.math.BigDecimal("8")); R result = service.vinEndChargeBillingCharge(vo); assertEquals(R.SUCCESS, result.getCode()); verify(gunClient, never()).updateChargingGunById(any(TChargingGun.class)); } // ===== VD:结算明细补齐计费策略明细id与首次添加时间 ===== @Test @SuppressWarnings("unchecked") void fillsVinSettlementDetailStrategyIdAndCreateTime() throws InterruptedException { TVinChargingOrderServiceImpl service = new TVinChargingOrderServiceImpl(); TVinChargingOrderMapper mapper = mock(TVinChargingOrderMapper.class); ChargingGunClient gunClient = mock(ChargingGunClient.class); TVinAccountingStrategyDetailOrderService detailOrderService = mock(TVinAccountingStrategyDetailOrderService.class); TVinChargingOrderAccountingStrategyService strategyService = mock(TVinChargingOrderAccountingStrategyService.class); TransactionTemplate txTemplate = mock(TransactionTemplate.class); ReflectionTestUtils.setField(service, "baseMapper", mapper); ReflectionTestUtils.setField(service, "chargingGunClient", gunClient); ReflectionTestUtils.setField(service, "vinAccountingStrategyDetailOrderService", detailOrderService); ReflectionTestUtils.setField(service, "vinChargingOrderAccountingStrategyService", strategyService); ReflectionTestUtils.setField(service, "transactionTemplate", txTemplate); ReflectionTestUtils.setField(service, "redissonClient", mockedRedisson(mockedLock(true))); TVinChargingOrder charging = new TVinChargingOrder(); charging.setId(2L); charging.setCode("VD1"); charging.setStatus(4); charging.setChargingGunId(7); when(mapper.selectOne(any())).thenReturn(charging); when(mapper.updateById(any())).thenReturn(1); TChargingGun gun = new TChargingGun(); gun.setId(7); gun.setStatus(4); R gunResult = gunOf(gun); when(gunClient.getChargingGunById(any())).thenReturn(gunResult); // 计费策略快照(尖段,电费1.0/服务费0.5),明细id=1920101(IdType.INPUT复制自原明细id) TVinAccountingStrategyDetailOrder snapshot = new TVinAccountingStrategyDetailOrder(); snapshot.setId(1920101); snapshot.setType(1); snapshot.setStartTime("00:00"); snapshot.setEndTime("06:00"); snapshot.setElectrovalence(new BigDecimal("1.0000")); snapshot.setServiceCharge(new BigDecimal("0.5000")); snapshot.setCostServiceCharge(new BigDecimal("0.5000")); LambdaQueryChainWrapper queryWrapper = mock(LambdaQueryChainWrapper.class); when(detailOrderService.lambdaQuery()).thenReturn(queryWrapper); when(queryWrapper.eq(any(), any())).thenReturn(queryWrapper); when(queryWrapper.list()).thenReturn(Collections.singletonList(snapshot)); LambdaUpdateChainWrapper updateWrapper = mock(LambdaUpdateChainWrapper.class); when(strategyService.lambdaUpdate()).thenReturn(updateWrapper); when(updateWrapper.eq(any(), any())).thenReturn(updateWrapper); when(updateWrapper.remove()).thenReturn(true); when(strategyService.saveBatch(any(Collection.class))).thenReturn(true); when(txTemplate.execute(any())).thenAnswer(invocation -> { TransactionCallback callback = invocation.getArgument(0); return callback.doInTransaction(mock(TransactionStatus.class)); }); TransactionRecordMessageVO vo = new TransactionRecordMessageVO(); vo.setTransaction_serial_number("VD1"); vo.setSpike_charge1(new BigDecimal("5")); R result = service.vinEndChargeBillingCharge(vo); assertEquals(R.SUCCESS, result.getCode()); ArgumentCaptor> captor = ArgumentCaptor.forClass(Collection.class); verify(strategyService).saveBatch(captor.capture()); List saved = new ArrayList<>(captor.getValue()); assertEquals(1, saved.size()); assertEquals(Integer.valueOf(1920101), saved.get(0).getAccountingStrategyDetailId()); assertNotNull(saved.get(0).getCreateTime()); assertEquals(Integer.valueOf(1), saved.get(0).getType()); assertEquals("00:00", saved.get(0).getStartTime()); assertEquals("06:00", saved.get(0).getEndTime()); } // ===== SD:结算明细补齐计费策略明细id与首次添加时间 ===== @Test @SuppressWarnings("unchecked") void fillsCardSettlementDetailStrategyIdAndCreateTime() throws InterruptedException { TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl(); TCardChargingOrderMapper mapper = mock(TCardChargingOrderMapper.class); ChargingCardClient cardClient = mock(ChargingCardClient.class); ChargingGunClient gunClient = mock(ChargingGunClient.class); TCardAccountingStrategyDetailOrderService detailOrderService = mock(TCardAccountingStrategyDetailOrderService.class); TCardChargingOrderAccountingStrategyService strategyService = mock(TCardChargingOrderAccountingStrategyService.class); TransactionTemplate txTemplate = mock(TransactionTemplate.class); ReflectionTestUtils.setField(service, "baseMapper", mapper); ReflectionTestUtils.setField(service, "chargingCardClient", cardClient); ReflectionTestUtils.setField(service, "chargingGunClient", gunClient); ReflectionTestUtils.setField(service, "cardAccountingStrategyDetailOrderService", detailOrderService); ReflectionTestUtils.setField(service, "cardChargingOrderAccountingStrategyService", strategyService); ReflectionTestUtils.setField(service, "transactionTemplate", txTemplate); ReflectionTestUtils.setField(service, "redissonClient", mockedRedisson(mockedLock(true))); TCardChargingOrder charging = new TCardChargingOrder(); charging.setId(1L); charging.setCode("SD1"); charging.setStatus(4); charging.setCardId(5L); charging.setChargingGunId(9); charging.setChargeAmount(new BigDecimal("20.00")); when(mapper.selectOne(any())).thenReturn(charging); when(mapper.updateById(any())).thenReturn(1); // 计费策略快照(尖段,电费1.0/服务费0.5),明细id=1910101(IdType.INPUT复制自原明细id) TCardAccountingStrategyDetailOrder snapshot = new TCardAccountingStrategyDetailOrder(); snapshot.setId(1910101); snapshot.setType(1); snapshot.setStartTime("00:00"); snapshot.setEndTime("06:00"); snapshot.setElectrovalence(new BigDecimal("1.0000")); snapshot.setServiceCharge(new BigDecimal("0.5000")); snapshot.setCostServiceCharge(new BigDecimal("0.5000")); LambdaQueryChainWrapper queryWrapper = mock(LambdaQueryChainWrapper.class); when(detailOrderService.lambdaQuery()).thenReturn(queryWrapper); when(queryWrapper.eq(any(), any())).thenReturn(queryWrapper); when(queryWrapper.list()).thenReturn(Collections.singletonList(snapshot)); LambdaUpdateChainWrapper updateWrapper = mock(LambdaUpdateChainWrapper.class); when(strategyService.lambdaUpdate()).thenReturn(updateWrapper); when(updateWrapper.eq(any(), any())).thenReturn(updateWrapper); when(updateWrapper.remove()).thenReturn(true); when(strategyService.saveBatch(any(Collection.class))).thenReturn(true); when(txTemplate.execute(any())).thenAnswer(invocation -> { TransactionCallback callback = invocation.getArgument(0); return callback.doInTransaction(mock(TransactionStatus.class)); }); // 扣款/解锁/复位枪桩成功返回,聚焦结算明细字段断言 ChargingCardDeductVO deductVO = new ChargingCardDeductVO(); R deductResult = mock(R.class); when(deductResult.getCode()).thenReturn(R.SUCCESS); when(deductResult.getData()).thenReturn(deductVO); when(cardClient.deductForCharging(any(com.ruoyi.account.api.dto.ChargingCardDeductDTO.class))) .thenReturn(deductResult); R unlockResult = okBoolean(); when(cardClient.unlockForCharging(anyLong(), anyString())).thenReturn(unlockResult); TChargingGun gun = new TChargingGun(); gun.setId(9); gun.setStatus(4); R gunResult = gunOf(gun); when(gunClient.getChargingGunById(any())).thenReturn(gunResult); R gunUpdateResult = mock(R.class); when(gunUpdateResult.getCode()).thenReturn(R.SUCCESS); when(gunClient.updateChargingGunById(any(TChargingGun.class))).thenReturn(gunUpdateResult); TransactionRecordMessageVO vo = new TransactionRecordMessageVO(); vo.setTransaction_serial_number("SD1"); vo.setSpike_charge1(new BigDecimal("5")); R result = service.cardEndChargeBillingCharge(vo); assertEquals(R.SUCCESS, result.getCode()); ArgumentCaptor> captor = ArgumentCaptor.forClass(Collection.class); verify(strategyService).saveBatch(captor.capture()); List saved = new ArrayList<>(captor.getValue()); assertEquals(1, saved.size()); assertEquals(Integer.valueOf(1910101), saved.get(0).getAccountingStrategyDetailId()); assertNotNull(saved.get(0).getCreateTime()); assertEquals(Integer.valueOf(1), saved.get(0).getType()); assertEquals("00:00", saved.get(0).getStartTime()); assertEquals("06:00", saved.get(0).getEndTime()); } @Test @SuppressWarnings("unchecked") void cardCompensationWritesElectricityToActualFlatPeriodIndex() { TCardChargingOrderServiceImpl service = spy(new TCardChargingOrderServiceImpl()); TCardAccountingStrategyDetailOrderService detailOrderService = mock(TCardAccountingStrategyDetailOrderService.class); ReflectionTestUtils.setField(service, "cardAccountingStrategyDetailOrderService", detailOrderService); TCardAccountingStrategyDetailOrder valley = new TCardAccountingStrategyDetailOrder(); valley.setType(4); valley.setStartTime("00:00"); TCardAccountingStrategyDetailOrder flat = new TCardAccountingStrategyDetailOrder(); flat.setType(3); flat.setStartTime("08:00"); LambdaQueryChainWrapper queryWrapper = mock(LambdaQueryChainWrapper.class); when(detailOrderService.lambdaQuery()).thenReturn(queryWrapper); when(queryWrapper.eq(any(), any())).thenReturn(queryWrapper); when(queryWrapper.list()).thenReturn(Arrays.asList(flat, valley)); doReturn(R.ok()).when(service).cardEndChargeBillingCharge(any(TransactionRecordMessageVO.class)); TCardChargingOrder order = new TCardChargingOrder(); order.setId(1L); order.setCode("SD-COMPENSATION-SLOT-2"); order.setChargingCapacity(new BigDecimal("17.36")); service.compensationSettle(order); ArgumentCaptor captor = ArgumentCaptor.forClass(TransactionRecordMessageVO.class); verify(service).cardEndChargeBillingCharge(captor.capture()); TransactionRecordMessageVO settlement = captor.getValue(); assertEquals("SD-COMPENSATION-SLOT-2", settlement.getTransaction_serial_number()); assertEquals(null, settlement.getFlat_charge1()); assertEquals(0, new BigDecimal("17.36").compareTo(settlement.getFlat_charge2())); assertEquals(0, new BigDecimal("17.36").compareTo(settlement.getTotal_electricity())); } @Test @SuppressWarnings("unchecked") void vinCompensationWritesElectricityToActualFlatPeriodIndex() { TVinChargingOrderServiceImpl service = spy(new TVinChargingOrderServiceImpl()); TVinAccountingStrategyDetailOrderService detailOrderService = mock(TVinAccountingStrategyDetailOrderService.class); ReflectionTestUtils.setField(service, "vinAccountingStrategyDetailOrderService", detailOrderService); TVinAccountingStrategyDetailOrder valley = new TVinAccountingStrategyDetailOrder(); valley.setType(4); valley.setStartTime("00:00"); TVinAccountingStrategyDetailOrder flat = new TVinAccountingStrategyDetailOrder(); flat.setType(3); flat.setStartTime("08:00"); LambdaQueryChainWrapper queryWrapper = mock(LambdaQueryChainWrapper.class); when(detailOrderService.lambdaQuery()).thenReturn(queryWrapper); when(queryWrapper.eq(any(), any())).thenReturn(queryWrapper); when(queryWrapper.list()).thenReturn(Arrays.asList(flat, valley)); doReturn(R.ok()).when(service).vinEndChargeBillingCharge(any(TransactionRecordMessageVO.class)); TVinChargingOrder order = new TVinChargingOrder(); order.setId(2L); order.setCode("VD-COMPENSATION-SLOT-2"); order.setChargingCapacity(new BigDecimal("9.87")); service.compensationSettle(order); ArgumentCaptor captor = ArgumentCaptor.forClass(TransactionRecordMessageVO.class); verify(service).vinEndChargeBillingCharge(captor.capture()); TransactionRecordMessageVO settlement = captor.getValue(); assertEquals("VD-COMPENSATION-SLOT-2", settlement.getTransaction_serial_number()); assertEquals(null, settlement.getFlat_charge1()); assertEquals(0, new BigDecimal("9.87").compareTo(settlement.getFlat_charge2())); assertEquals(0, new BigDecimal("9.87").compareTo(settlement.getTotal_electricity())); } }