|
|
@@ -355,6 +355,10 @@ class LsyOnboardingServiceTest {
|
|
|
* <p>★ 填 {@code ""} 比留 null 更坏:{@code address_province} 这类字段会带着空串
|
|
|
* 进**签名原文**(本仓规则:null 不参与、**空串参与**),报文与签名一起变,
|
|
|
* 而出错只在上游。
|
|
|
+ *
|
|
|
+ * <p>★ 三种输入的 {@code provinceCode} 期望**各由本用例自己断言**(前两格必须 Java null、
|
|
|
+ * 第三格必须原值):这一格此前只由 {@code areaList_carriesProvinceCode_atLevel1} 兜着,
|
|
|
+ * 本条对它自己声明的第 ②③ 条毫无断言(F1)。
|
|
|
*/
|
|
|
@Test
|
|
|
void areaList_missingGbCode_leavesFieldNull() {
|
|
|
@@ -363,12 +367,18 @@ class LsyOnboardingServiceTest {
|
|
|
ok(",\"area_list\":[{\"area_name\":\"某区\",\"area_code\":\"1\",\"province_code\":null}]"),
|
|
|
ok(",\"area_list\":[{\"area_name\":\"某区\",\"area_code\":\"3\",\"province_code\":\"110000\"}]"),
|
|
|
};
|
|
|
- for (String json : jsons) {
|
|
|
+ // 与 jsons 一一对应的 provinceCode 期望:前两格(缺键 / JSON null)必须是 Java null;
|
|
|
+ // 第三格是三种输入里唯一真正给了省码的 ⇒ 必须是原值,不是 "null" 也不是 ""。
|
|
|
+ String[] expectedProvince = {null, null, "110000"};
|
|
|
+ for (int i = 0; i < jsons.length; i++) {
|
|
|
+ String json = jsons[i];
|
|
|
stubUpstream(json);
|
|
|
|
|
|
List<LsyAreaItemDTO> areas = service.areaList("1", null);
|
|
|
|
|
|
assertEquals(1, areas.size(), json);
|
|
|
+ assertEquals(expectedProvince[i], areas.get(0).getProvinceCode(),
|
|
|
+ "province_code 的期望按输入而异(缺键 / JSON null ⇒ Java null;给了值 ⇒ 原值):" + json);
|
|
|
assertNull(areas.get(0).getCountyCode(), "缺键 / JSON null ⇒ 必须是 Java null:" + json);
|
|
|
assertNull(areas.get(0).getCityCode(), "缺键 / JSON null ⇒ 必须是 Java null:" + json);
|
|
|
}
|
|
|
@@ -2714,6 +2724,33 @@ class LsyOnboardingServiceTest {
|
|
|
"出站参数必须恰好是服务拥有的 4 个键(inst_no / sign 归客户端补):" + sent);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * ★ {@code channel_type} 的空白处理与 {@code channel_id} **同口径:trim**
|
|
|
+ * (先例:{@link #channelId_paddedConfig_trimmedIdenticallyOnAllFourLegs})。
|
|
|
+ *
|
|
|
+ * <p>为什么单独一条:{@code mccList} 是唯一用 {@code channel_type} 的腿,而
|
|
|
+ * {@link #mccList_sendsChannelTypeFromConfig} 用的配置值 {@code "3"} 本来就无空白
|
|
|
+ * ⇒ 把生产代码里的 {@code trimOrNull} 去掉,它**照样绿**(实测:该变异下它绿、
|
|
|
+ * 本用例红)。两个字段同源(都取自配置、都进**签名原文**),而配置来自**环境变量**
|
|
|
+ * (用户手工注入),带首尾空白是现实风险 —— 症状是上游回一句签名错误,本侧看不出是空白。
|
|
|
+ *
|
|
|
+ * <p>★ 本用例**不碰共享常量** {@code CFG_CHANNEL_TYPE}:它在
|
|
|
+ * {@code withOnboardingCredentials()} 里是全体用例的公共输入,改它会波及全文件。
|
|
|
+ * 这里照夹具配齐后,只在本用例内覆盖这一个字段。
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ void channelType_paddedConfig_trimmedOnMccList() {
|
|
|
+ withOnboardingCredentials();
|
|
|
+ props.setChannelType(" " + CFG_CHANNEL_TYPE + " ");
|
|
|
+ stubUpstream(MCC_LIST_EXAMPLE);
|
|
|
+
|
|
|
+ service.mccList("2", "420100", null);
|
|
|
+
|
|
|
+ Map<String, Object> sent = sentParams("/api/merchant/getTopMccByType");
|
|
|
+ assertEquals(CFG_CHANNEL_TYPE, sent.get("channel_type"),
|
|
|
+ "配置带首尾空白时 channel_type 必须发 trim 后的值(与 channel_id 四腿同口径):" + sent);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* ★ 「1 级不填 {@code parent_id}」的判据是 **level**,不是「{@code parentId} 是不是 null」
|
|
|
* —— 与 {@link #areaList_level1_omitsParentCode} 逐字同一条规则(该页参数表写
|
|
|
@@ -2864,10 +2901,15 @@ class LsyOnboardingServiceTest {
|
|
|
* —— 差 2,同 {@link #anxinSignPerson_sendsAllSevenParams}({@code inst_no} / {@code sign} 归客户端补)。
|
|
|
*
|
|
|
* <p>比个人版多的正是四个键:{@code business_licence} / {@code merchant_address} /
|
|
|
- * {@code legal_cert_no} / {@code legal_name}。这里**逐个断言值**、且四个值两两不同,
|
|
|
- * 是为了让「公司版复用了个人版的组装、漏掉了多的那四个」与
|
|
|
- * 「四个里取错了一个 getter」这两种实现都过不了集合相等这一关(漏键会红、
|
|
|
- * 取错 getter 会让值对不上)。
|
|
|
+ * {@code legal_cert_no} / {@code legal_name}。这里**9 个键逐个断言值**,是为了让
|
|
|
+ * 「公司版复用了个人版的组装、漏掉了多的那四个」与「某一个键取错了 getter」这两种实现
|
|
|
+ * 都过不了(漏键会红、取错 getter 会让值对不上)。
|
|
|
+ *
|
|
|
+ * <p>★ <b>9 个夹具值实测两两不同</b>(4 个 {@code ANXIN_*} 常量值互不相同,5 个与键同名的
|
|
|
+ * 字面量也互不相同)—— 这是值断言有分辨力的**前提**:只要有两个键同值,
|
|
|
+ * 把这两个 getter 互换就照样绿,那几行断言等于摆设。改夹具时先重量这一点。
|
|
|
+ * 未断言的 5 个里 {@code principal_cert_no} 与 {@code legal_cert_no} 尤其要紧:
|
|
|
+ * 它们是**同一类 PII 的两个不同人**(结算人 / 法人),取错不会抛异常。
|
|
|
*/
|
|
|
@Test
|
|
|
void anxinSignCompany_sendsAllElevenParams() {
|
|
|
@@ -2881,6 +2923,12 @@ class LsyOnboardingServiceTest {
|
|
|
"merchant_address", "legal_cert_no", "legal_name"), sent.keySet(),
|
|
|
"出站参数必须恰好是服务拥有的 9 个键(inst_no / sign 归客户端补;"
|
|
|
+ "用例名里的 11 是上游参数表的行数):" + sent);
|
|
|
+ // 下面 9 行覆盖全部 9 个键:5 个与个人腿共用的(取错 getter 只会静默发错人)+ 4 个公司腿独有的。
|
|
|
+ assertEquals(ANXIN_CONTACT_PHONE, sent.get("contact_phone"));
|
|
|
+ assertEquals(ANXIN_PRINCIPAL_CERT_NO, sent.get("principal_cert_no"));
|
|
|
+ assertEquals("account_card_name", sent.get("account_card_name"));
|
|
|
+ assertEquals(ANXIN_ACCOUNT_CARD_NUM, sent.get("account_card_num"));
|
|
|
+ assertEquals("merchant_name", sent.get("merchant_name"));
|
|
|
assertEquals("business_licence", sent.get("business_licence"));
|
|
|
assertEquals("merchant_address", sent.get("merchant_address"));
|
|
|
assertEquals(ANXIN_LEGAL_CERT_NO, sent.get("legal_cert_no"));
|