xiaoyi
9 天以前 2b161b1f1401c89fa927e390d78ff49568337f6c
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
package cn.iocoder.yudao.module.mes.service.safety;
 
import cn.iocoder.yudao.module.hrm.api.employee.HrmEmployeeApi;
import cn.iocoder.yudao.module.hrm.api.employee.dto.HrmEmployeeSimpleDTO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkshopDO;
 
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.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
 
import java.util.List;
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;
 
/**
 * {@link SafetyRefResolver} 空集合场景回归测试
 *
 * <p>背景:{@code Map.of()} 是空且不可变的 Map,它的 {@code get(null)} 会抛 NPE,
 * 而 {@code Map.of().get(非null)} 不会。安全生产模块里「组织 / 证件 / 隐患」等
 * 记录在未关联员工(leaderId、employeeId 为 null)时,就会走到 {@code map.get(null)},
 * 从而在列表页直接 500。</p>
 *
 * <p>这里锁死约定:空集合必须返回可接受 null key 的空 Map。</p>
 */
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class SafetyRefResolverEmptyCollectionTest {
 
    @InjectMocks
    private SafetyRefResolver resolver;
 
    @Mock
    private HrmEmployeeApi hrmEmployeeApi;
    @Mock
    private cn.iocoder.yudao.module.mes.dal.mysql.md.workstation.MesMdWorkshopMapper workshopMapper;
 
    /** 空集合:必须能 get(null) 而不抛 NPE(这就是线上 NPE 的根因) */
    @Test
    void employeeMap_emptyCollection_getNullShouldNotThrow() {
        Map<Long, HrmEmployeeSimpleDTO> map = resolver.employeeMap(List.of());
        assertTrue(map.isEmpty());
        // Map.of() 在这里会抛 NullPointerException
        assertNull(map.get(null), "空集合返回的 Map 必须允许用 null 作为 key 查询");
    }
 
    /** 集合里全是 null:过滤后为空,同样必须能 get(null) */
    @Test
    void employeeMap_allNullElements_getNullShouldNotThrow() {
        Map<Long, HrmEmployeeSimpleDTO> map = resolver.employeeMap(java.util.Arrays.asList((Long) null, null));
        assertTrue(map.isEmpty());
        assertNull(map.get(null));
    }
 
    /** null 集合本身 */
    @Test
    void employeeMap_nullCollection_getNullShouldNotThrow() {
        Map<Long, HrmEmployeeSimpleDTO> map = resolver.employeeMap(null);
        assertTrue(map.isEmpty());
        assertNull(map.get(null));
    }
 
    @Test
    void workshopMap_emptyCollection_getNullShouldNotThrow() {
        Map<Long, MesMdWorkshopDO> map = resolver.workshopMap(List.of());
        assertTrue(map.isEmpty());
        assertNull(map.get(null), "空集合返回的 Map 必须允许用 null 作为 key 查询");
    }
 
    @Test
    void workshopMap_allNullElements_getNullShouldNotThrow() {
        Map<Long, MesMdWorkshopDO> map = resolver.workshopMap(java.util.Arrays.asList((Long) null));
        assertTrue(map.isEmpty());
        assertNull(map.get(null));
    }
 
    @Test
    void workshopMap_nullCollection_getNullShouldNotThrow() {
        Map<Long, MesMdWorkshopDO> map = resolver.workshopMap(null);
        assertTrue(map.isEmpty());
        assertNull(map.get(null));
    }
 
    /** 返回的 Map 应该是可变的(避免后续 put 抛 UnsupportedOperationException) */
    @Test
    void employeeMap_emptyResultShouldBeMutable() {
        Map<Long, HrmEmployeeSimpleDTO> map = resolver.employeeMap(List.of());
        map.put(1L, new HrmEmployeeSimpleDTO());
        assertEquals(1, map.size());
    }
 
    @Test
    void workshopMap_emptyResultShouldBeMutable() {
        Map<Long, MesMdWorkshopDO> map = resolver.workshopMap(List.of());
        map.put(1L, new MesMdWorkshopDO());
        assertEquals(1, map.size());
    }
 
}