|
|
@@ -128,10 +128,13 @@ class LsyOnboardingServiceTest {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * ★ 这条钉上游数据的**真实形状**:page 196236568 的返回示例里 {@code area_code}
|
|
|
+ * ★ 这条钉的是**文档示例**的形状:page 196236568 的返回示例里 {@code area_code}
|
|
|
* 出现 {@code 100A}…{@code 100H},其中 {@code 100G} / {@code 100H} **不是合法十六进制**
|
|
|
- * (连十六进制都不是,更不是十进制)。任何 {@code Integer.parseInt} / {@code Long.parseLong} /
|
|
|
- * 数字型 DTO 字段都会在这里炸 —— 而炸的是三级联动的第一屏。
|
|
|
+ * (连十六进制都不是,更不是十进制)⇒ 若哪天真发字符串,数字型字段/解析必炸。
|
|
|
+ *
|
|
|
+ * <p>注意 **{@code 100G} 在真机 483 条里一次都没出现过**(2026-09-22 普查)——
|
|
|
+ * 文档形态与活服务形态各一条用例,缺一条就有一种形态零覆盖:见下一条
|
|
|
+ * {@link #areaList_areaCode_integerShape_isStringified}。
|
|
|
*/
|
|
|
@Test
|
|
|
void areaList_areaCode_isString_notNumber() {
|
|
|
@@ -146,6 +149,30 @@ class LsyOnboardingServiceTest {
|
|
|
assertEquals("100G", code);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * ★ 这条钉的是**活服务的真实形态**:2026-09-22 真机普查 483 条,{@code area_code}
|
|
|
+ * 的运行期类型**全是 {@code Integer}(483/483)、非数字形态 0 条**。桩回数字 {@code 1}
|
|
|
+ * ⇒ 服务必须取回**字符串** {@code "1"}。
|
|
|
+ *
|
|
|
+ * <p>为什么非有这条不可:上一条({@code "100G"})覆盖的是**文档示例**的形态,而真机上
|
|
|
+ * 会发生的数字形态此前**零覆盖** —— 把 {@code asText} 改成 {@code (String) m.get("area_code")}
|
|
|
+ * 能让上一条与其余用例全绿,却在活服务上抛 {@code ClassCastException}(M-1 变异读数)。
|
|
|
+ * 夹具与真机取证同形:{@code level=2} + {@code parent_code="1"}(真机实测这一组才返回条目)。
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ void areaList_areaCode_integerShape_isStringified() {
|
|
|
+ stubUpstream(ok(",\"area_list\":[{\"area_name\":\"市辖区\",\"area_code\":1}]"));
|
|
|
+
|
|
|
+ List<LsyAreaItemDTO> areas = service.areaList("2", "1");
|
|
|
+
|
|
|
+ assertEquals(1, areas.size());
|
|
|
+ Object code = areas.get(0).getAreaCode();
|
|
|
+ assertInstanceOf(String.class, code,
|
|
|
+ "活服务发的是数字,服务必须把它取成字符串而不是强转");
|
|
|
+ assertEquals("1", code);
|
|
|
+ assertEquals("市辖区", areas.get(0).getAreaName());
|
|
|
+ }
|
|
|
+
|
|
|
/** 契约明写的三种「防御性读取」输入之一:上游没返回 area_list 这个键。 */
|
|
|
@Test
|
|
|
void areaList_blankList_returnsEmpty() {
|