puzhibing
2026-09-29 a70433b2ee5bb37823ab73422a01251343cb5f58
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
package com.ruoyi.other.service.impl;
 
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.account.api.dto.VinManagementQueryDTO;
import com.ruoyi.account.api.feignClient.VinManagementClient;
import com.ruoyi.account.api.model.TVinManagement;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.other.api.domain.TChargeAuthorization;
import com.ruoyi.other.api.domain.TFleet;
import com.ruoyi.other.api.feignClient.FleetOrderAggregateClient;
import com.ruoyi.other.api.vo.FleetOrderAggregateVO;
import com.ruoyi.other.mapper.TChargeAuthorizationMapper;
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.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.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
 
/**
 * 车队服务单测(覆盖 VIN 列表分页代理 + 5 列聚合 fillAggregates)。
 * 远程客户端和 Mapper 以 Mock 替代,不依赖 Spring 容器与数据库。
 */
class TFleetServiceImplTest {
 
    @Test
    void passesFleetIdAndPagingToVinService() {
        VinManagementClient client = Mockito.mock(VinManagementClient.class);
        Page<TVinManagement> expected = new Page<>(1, 10);
        expected.setTotal(1);
        expected.setRecords(Collections.singletonList(vehicle()));
        Mockito.when(client.getVinPageByFleet(Mockito.any())).thenReturn(R.ok(expected));
 
        Page<TVinManagement> actual = buildService(fleet(4), client, null, null).selectVinPage(4, 1, 10);
 
        assertSame(expected, actual);
        ArgumentCaptor<VinManagementQueryDTO> captor = ArgumentCaptor.forClass(VinManagementQueryDTO.class);
        Mockito.verify(client).getVinPageByFleet(captor.capture());
        assertEquals(4, captor.getValue().getFleetId());
        assertEquals(1, captor.getValue().getPageCurr());
        assertEquals(10, captor.getValue().getPageSize());
    }
 
    @Test
    void fallsBackToDefaultPagingWhenParamsInvalid() {
        VinManagementClient client = Mockito.mock(VinManagementClient.class);
        Mockito.when(client.getVinPageByFleet(Mockito.any())).thenReturn(R.ok(new Page<>(1, 10)));
 
        buildService(fleet(5), client, null, null).selectVinPage(5, null, 0);
 
        ArgumentCaptor<VinManagementQueryDTO> captor = ArgumentCaptor.forClass(VinManagementQueryDTO.class);
        Mockito.verify(client).getVinPageByFleet(captor.capture());
        assertEquals(1, captor.getValue().getPageCurr());
        assertEquals(10, captor.getValue().getPageSize());
    }
 
    @Test
    void rejectsMissingFleetId() {
        VinManagementClient client = Mockito.mock(VinManagementClient.class);
        TFleetServiceImpl service = buildService(null, client, null, null);
 
        ServiceException ex = assertThrows(ServiceException.class, () -> service.selectVinPage(null, 1, 10));
 
        assertTrue(ex.getMessage().contains("车队ID不能为空"), ex.getMessage());
        Mockito.verifyNoInteractions(client);
    }
 
    @Test
    void rejectsUnknownFleet() {
        VinManagementClient client = Mockito.mock(VinManagementClient.class);
        TFleetServiceImpl service = buildService(null, client, null, null);
 
        ServiceException ex = assertThrows(ServiceException.class, () -> service.selectVinPage(9, 1, 10));
 
        assertTrue(ex.getMessage().contains("车队不存在"), ex.getMessage());
        Mockito.verifyNoInteractions(client);
    }
 
    @Test
    void failsWhenRemoteReturnsError() {
        VinManagementClient client = Mockito.mock(VinManagementClient.class);
        Mockito.when(client.getVinPageByFleet(Mockito.any())).thenReturn(R.fail("VIN 管理服务调用失败"));
 
        ServiceException ex = assertThrows(ServiceException.class,
                () -> buildService(fleet(4), client, null, null).selectVinPage(4, 1, 10));
 
        assertTrue(ex.getMessage().contains("VIN码车辆查询失败"), ex.getMessage());
    }
 
    @Test
    void failsWhenRemoteReturnsNullData() {
        VinManagementClient client = Mockito.mock(VinManagementClient.class);
        Mockito.when(client.getVinPageByFleet(Mockito.any())).thenReturn(null);
 
        ServiceException ex = assertThrows(ServiceException.class,
                () -> buildService(fleet(4), client, null, null).selectVinPage(4, 1, 10));
 
        assertTrue(ex.getMessage().contains("服务无响应"), ex.getMessage());
    }
 
    @Test
    void fillAggregatesPopulatesAllFiveFields() {
        VinManagementClient vinClient = Mockito.mock(VinManagementClient.class);
        FleetOrderAggregateClient aggClient = Mockito.mock(FleetOrderAggregateClient.class);
        TChargeAuthorizationMapper authMapper = Mockito.mock(TChargeAuthorizationMapper.class);
 
        TFleet fleet = fleet(101);
        fleet.setCompanyId(7);
 
        Mockito.when(vinClient.countByFleet(101)).thenReturn(R.ok(8L));
 
        FleetOrderAggregateVO vo = new FleetOrderAggregateVO();
        vo.setCumulativeCharge(new BigDecimal("12.34"));
        vo.setCumulativeElectrovalence(new BigDecimal("56.78"));
        vo.setCumulativeServiceCharge(new BigDecimal("9.10"));
        Mockito.when(aggClient.aggregateByFleet(101)).thenReturn(R.ok(vo));
 
        TChargeAuthorization auth = new TChargeAuthorization();
        auth.setCompanyId(7);
        auth.setSiteIds("1,2,3,2,1");
        Mockito.when(authMapper.selectList(Mockito.any())).thenReturn(Collections.singletonList(auth));
 
        TFleetServiceImpl service = buildService(fleet, vinClient, aggClient, authMapper);
        service.fillAggregates(Arrays.asList(fleet));
 
        assertEquals(8L, fleet.getVinCount());
        assertEquals(3L, fleet.getStationCount());
        assertNotNull(fleet.getCumulativeCharge());
        assertEquals(0, new BigDecimal("12.34").compareTo(fleet.getCumulativeCharge()));
        assertEquals(0, new BigDecimal("56.78").compareTo(fleet.getCumulativeElectrovalence()));
        assertEquals(0, new BigDecimal("9.10").compareTo(fleet.getCumulativeServiceCharge()));
    }
 
    @Test
    void fillAggregatesHandlesNullFleetIdSafely() {
        VinManagementClient vinClient = Mockito.mock(VinManagementClient.class);
        FleetOrderAggregateClient aggClient = Mockito.mock(FleetOrderAggregateClient.class);
        TChargeAuthorizationMapper authMapper = Mockito.mock(TChargeAuthorizationMapper.class);
        TFleetServiceImpl service = buildService(null, vinClient, aggClient, authMapper);
 
        // 传入空集合 / null 不抛异常
        service.fillAggregates(null);
        service.fillAggregates(Collections.emptyList());
        Mockito.verifyNoInteractions(vinClient, aggClient, authMapper);
    }
 
    @Test
    void fillAggregatesFallsBackToZeroOnRemoteFailure() {
        VinManagementClient vinClient = Mockito.mock(VinManagementClient.class);
        FleetOrderAggregateClient aggClient = Mockito.mock(FleetOrderAggregateClient.class);
        TChargeAuthorizationMapper authMapper = Mockito.mock(TChargeAuthorizationMapper.class);
 
        TFleet fleet = fleet(202);
        fleet.setCompanyId(null);
        Mockito.when(vinClient.countByFleet(202)).thenReturn(R.fail("down"));
        Mockito.when(aggClient.aggregateByFleet(202)).thenReturn(null);
        Mockito.when(authMapper.selectList(Mockito.any())).thenReturn(Collections.emptyList());
 
        TFleetServiceImpl service = buildService(fleet, vinClient, aggClient, authMapper);
        service.fillAggregates(Arrays.asList(fleet));
 
        assertEquals(0L, fleet.getVinCount());
        assertEquals(0L, fleet.getStationCount());
        assertEquals(BigDecimal.ZERO, fleet.getCumulativeCharge());
        assertEquals(BigDecimal.ZERO, fleet.getCumulativeElectrovalence());
        assertEquals(BigDecimal.ZERO, fleet.getCumulativeServiceCharge());
    }
 
    private TFleetServiceImpl buildService(TFleet fleet, VinManagementClient client,
                                           FleetOrderAggregateClient aggClient,
                                           TChargeAuthorizationMapper authMapper) {
        TFleetServiceImpl service = Mockito.spy(new TFleetServiceImpl());
        Mockito.doReturn(fleet).when(service).getById(Mockito.any());
        ReflectionTestUtils.setField(service, "vinManagementClient", client);
        ReflectionTestUtils.setField(service, "fleetOrderAggregateClient", aggClient);
        ReflectionTestUtils.setField(service, "chargeAuthorizationMapper", authMapper);
        return service;
    }
 
    private TFleet fleet(Integer id) {
        TFleet fleet = new TFleet();
        fleet.setId(id);
        return fleet;
    }
 
    private TVinManagement vehicle() {
        TVinManagement item = new TVinManagement();
        item.setId(1L);
        item.setVin("12345678900000000");
        item.setPlateNumber("川A123456");
        item.setFleetId(4);
        item.setBalance(new BigDecimal("30.00"));
        item.setStatus(1);
        return item;
    }
}