2 天以前 eccad5a129106377a275be4f7cdc58e99e9b95d4
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
206
207
208
209
210
211
package cn.iocoder.yudao.module.mes.service.md.autocode;
 
import cn.hutool.core.util.ReflectUtil;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.autocode.MesMdAutoCodePartDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.autocode.MesMdAutoCodeRecordDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.autocode.MesMdAutoCodeRuleDO;
import cn.iocoder.yudao.module.mes.dal.mysql.md.autocode.MesMdAutoCodeRecordMapper;
import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodePartTypeEnum;
import cn.iocoder.yudao.module.mes.service.md.autocode.strategy.MesMdAutoCodeContext;
import cn.iocoder.yudao.module.mes.service.md.autocode.strategy.MesMdAutoCodePartStrategy;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
 
import java.util.Arrays;
import java.util.List;
 
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
 
/**
 * {@link MesMdAutoCodeRecordServiceImpl} 的单元测试
 *
 * @author 芋道源码
 */
@ExtendWith(MockitoExtension.class)
public class MesMdAutoCodeRecordServiceImplTest {
 
    @InjectMocks
    private MesMdAutoCodeRecordServiceImpl recordService;
 
    @Mock
    private MesMdAutoCodeRecordMapper recordMapper;
 
    @Mock
    private MesMdAutoCodeRuleService ruleService;
    @Mock
    private MesMdAutoCodePartService partService;
 
    @Mock
    private MesMdAutoCodePartStrategy fixedCharStrategy;
    @Mock
    private MesMdAutoCodePartStrategy serialNumberStrategy;
    @Mock
    private MesMdAutoCodePartStrategy inputCharStrategy;
    @Mock
    private MesMdAutoCodePartStrategy dateStrategy;
 
    @BeforeEach
    public void setUp() {
        // 使用反射注入 strategyList
        List<MesMdAutoCodePartStrategy> strategyList = Arrays.asList(
                fixedCharStrategy, serialNumberStrategy, inputCharStrategy, dateStrategy
        );
        when(fixedCharStrategy.getType()).thenReturn(MesMdAutoCodePartTypeEnum.FIXED_CHAR.getType());
        when(serialNumberStrategy.getType()).thenReturn(MesMdAutoCodePartTypeEnum.SERIAL_NUMBER.getType());
        when(inputCharStrategy.getType()).thenReturn(MesMdAutoCodePartTypeEnum.INPUT_CHAR.getType());
        when(dateStrategy.getType()).thenReturn(MesMdAutoCodePartTypeEnum.DATE.getType());
        ReflectUtil.setFieldValue(recordService, "strategyList", strategyList);
        // 手动调用 init 方法初始化策略 map
        recordService.init();
    }
 
    @Test
    public void testGenerateAutoCode_fixedCharAndSerialNumber() {
        // 准备参数
        String ruleCode = "ITEM_CODE";
        MesMdAutoCodeRuleDO rule = new MesMdAutoCodeRuleDO().setId(1L).setCode(ruleCode).setPadded(false);
        MesMdAutoCodePartDO part1 = new MesMdAutoCodePartDO().setType(MesMdAutoCodePartTypeEnum.FIXED_CHAR.getType())
                .setFixCharacter("ITEM_").setLength(5).setSort(1);
        MesMdAutoCodePartDO part2 = new MesMdAutoCodePartDO().setType(MesMdAutoCodePartTypeEnum.SERIAL_NUMBER.getType())
                .setSerialStartNo(1).setSerialStep(1).setLength(4).setSort(2).setCycleFlag(false);
        // mock
        when(ruleService.getAutoCodeRuleByCode(ruleCode)).thenReturn(rule);
        when(partService.getAutoCodePartListByRuleId(1L)).thenReturn(Arrays.asList(part1, part2));
        when(fixedCharStrategy.generate(eq(part1), any(MesMdAutoCodeContext.class))).thenReturn("ITEM_");
        when(serialNumberStrategy.generate(eq(part2), any(MesMdAutoCodeContext.class))).thenAnswer(invocation -> {
            MesMdAutoCodeContext context = invocation.getArgument(1);
            context.setSerialNo(1L);
            return "0001";
        });
        when(recordMapper.selectByResult("ITEM_0001")).thenReturn(null);
 
        // 调用
        String result = recordService.generateAutoCode(ruleCode, null);
        // 断言
        assertEquals("ITEM_0001", result);
        ArgumentCaptor<MesMdAutoCodeRecordDO> captor = ArgumentCaptor.forClass(MesMdAutoCodeRecordDO.class);
        verify(recordMapper).insert(captor.capture());
        MesMdAutoCodeRecordDO record = captor.getValue();
        assertEquals(1L, record.getRuleId());
        assertEquals("ITEM_0001", record.getResult());
        assertEquals(1, record.getSerialNo());
    }
 
    @Test
    public void testGenerateAutoCode_retryWhenResultExists() {
        // 准备参数
        String ruleCode = "DV_MACHINERY_CODE";
        MesMdAutoCodeRuleDO rule = new MesMdAutoCodeRuleDO().setId(5L).setCode(ruleCode).setPadded(false);
        MesMdAutoCodePartDO part1 = new MesMdAutoCodePartDO().setType(MesMdAutoCodePartTypeEnum.FIXED_CHAR.getType())
                .setFixCharacter("M").setLength(1).setSort(1);
        MesMdAutoCodePartDO part2 = new MesMdAutoCodePartDO().setType(MesMdAutoCodePartTypeEnum.SERIAL_NUMBER.getType())
                .setSerialStartNo(1).setSerialStep(1).setLength(5).setSort(2).setCycleFlag(false);
        // mock
        when(ruleService.getAutoCodeRuleByCode(ruleCode)).thenReturn(rule);
        when(partService.getAutoCodePartListByRuleId(5L)).thenReturn(Arrays.asList(part1, part2));
        when(fixedCharStrategy.generate(eq(part1), any(MesMdAutoCodeContext.class))).thenReturn("M");
        long[] serialNoRef = {0L};
        when(serialNumberStrategy.generate(eq(part2), any(MesMdAutoCodeContext.class))).thenAnswer(invocation -> {
            MesMdAutoCodeContext context = invocation.getArgument(1);
            long serialNo = ++serialNoRef[0];
            context.setSerialNo(serialNo);
            return String.format("%05d", serialNo);
        });
        when(recordMapper.selectByResult("M00001")).thenReturn(new MesMdAutoCodeRecordDO());
        when(recordMapper.selectByResult("M00002")).thenReturn(new MesMdAutoCodeRecordDO());
        when(recordMapper.selectByResult("M00003")).thenReturn(null);
 
        // 调用
        String result = recordService.generateAutoCode(ruleCode, null);
        // 断言
        assertEquals("M00003", result);
        ArgumentCaptor<MesMdAutoCodeRecordDO> captor = ArgumentCaptor.forClass(MesMdAutoCodeRecordDO.class);
        verify(recordMapper).insert(captor.capture());
        MesMdAutoCodeRecordDO record = captor.getValue();
        assertEquals(5L, record.getRuleId());
        assertEquals("M00003", record.getResult());
        assertEquals(3L, record.getSerialNo());
    }
 
    @Test
    public void testGenerateAutoCode_withInputChar() {
        // 准备参数
        String ruleCode = "CLIENT_CODE";
        String inputChar = "A";
        MesMdAutoCodeRuleDO rule = new MesMdAutoCodeRuleDO().setId(2L).setCode(ruleCode).setPadded(false);
        MesMdAutoCodePartDO part1 = new MesMdAutoCodePartDO().setType(MesMdAutoCodePartTypeEnum.INPUT_CHAR.getType())
                .setLength(1).setSort(1);
        MesMdAutoCodePartDO part2 = new MesMdAutoCodePartDO().setType(MesMdAutoCodePartTypeEnum.SERIAL_NUMBER.getType())
                .setSerialStartNo(1).setSerialStep(1).setLength(4).setSort(2).setCycleFlag(false);
        // mock
        when(ruleService.getAutoCodeRuleByCode(ruleCode)).thenReturn(rule);
        when(partService.getAutoCodePartListByRuleId(2L)).thenReturn(Arrays.asList(part1, part2));
        when(inputCharStrategy.generate(eq(part1), any(MesMdAutoCodeContext.class))).thenReturn("A");
        when(serialNumberStrategy.generate(eq(part2), any(MesMdAutoCodeContext.class))).thenReturn("0001");
        when(recordMapper.selectByResult("A0001")).thenReturn(null);
 
        // 调用
        String result = recordService.generateAutoCode(ruleCode, inputChar);
        // 断言
        assertEquals("A0001", result);
        ArgumentCaptor<MesMdAutoCodeRecordDO> captor = ArgumentCaptor.forClass(MesMdAutoCodeRecordDO.class);
        verify(recordMapper).insert(captor.capture());
        MesMdAutoCodeRecordDO record = captor.getValue();
        assertEquals(inputChar, record.getInputChar());
        assertEquals("A0001", record.getResult());
    }
 
    @Test
    public void testGenerateAutoCode_withPadding() {
        // 准备参数
        String ruleCode = "PADDED_CODE";
        MesMdAutoCodeRuleDO rule = new MesMdAutoCodeRuleDO().setId(3L).setCode(ruleCode)
                .setPadded(true).setMaxLength(10).setPaddedChar("0").setPaddedMethod(1);
        MesMdAutoCodePartDO part1 = new MesMdAutoCodePartDO().setType(MesMdAutoCodePartTypeEnum.FIXED_CHAR.getType())
                .setFixCharacter("IT").setLength(2).setSort(1);
        // mock
        when(ruleService.getAutoCodeRuleByCode(ruleCode)).thenReturn(rule);
        when(partService.getAutoCodePartListByRuleId(3L)).thenReturn(Arrays.asList(part1));
        when(fixedCharStrategy.generate(eq(part1), any(MesMdAutoCodeContext.class))).thenReturn("IT");
        when(recordMapper.selectByResult("00000000IT")).thenReturn(null);
 
        // 调用
        String result = recordService.generateAutoCode(ruleCode, null);
        // 断言:IT 补齐到 10 位,左补 0
        assertEquals("00000000IT", result);
        verify(recordMapper).insert(any(MesMdAutoCodeRecordDO.class));
    }
 
    @Test
    public void testGenerateAutoCode_withDatePart() {
        // 准备参数
        String ruleCode = "DATE_CODE";
        MesMdAutoCodeRuleDO rule = new MesMdAutoCodeRuleDO().setId(4L).setCode(ruleCode).setPadded(false);
        MesMdAutoCodePartDO part1 = new MesMdAutoCodePartDO().setType(MesMdAutoCodePartTypeEnum.DATE.getType())
                .setDateFormat("yyyyMMdd").setLength(8).setSort(1);
        MesMdAutoCodePartDO part2 = new MesMdAutoCodePartDO().setType(MesMdAutoCodePartTypeEnum.SERIAL_NUMBER.getType())
                .setSerialStartNo(1).setSerialStep(1).setLength(4).setSort(2).setCycleFlag(false);
 
        // mock
        when(ruleService.getAutoCodeRuleByCode(ruleCode)).thenReturn(rule);
        when(partService.getAutoCodePartListByRuleId(4L)).thenReturn(Arrays.asList(part1, part2));
        when(dateStrategy.generate(eq(part1), any(MesMdAutoCodeContext.class))).thenReturn("20260304");
        when(serialNumberStrategy.generate(eq(part2), any(MesMdAutoCodeContext.class))).thenReturn("0001");
        when(recordMapper.selectByResult("202603040001")).thenReturn(null);
 
        // 调用
        String result = recordService.generateAutoCode(ruleCode, null);
        // 断言:日期 8 位 + 流水号 4 位 = 12 位
        assertEquals(12, result.length());
        assertEquals("202603040001", result);
        verify(recordMapper).insert(any(MesMdAutoCodeRecordDO.class));
    }
 
}