|
@@ -285,38 +285,40 @@ class ExamSprintReportApplicationServiceTest {
|
|
|
.isEqualTo(ErrorCode.VALIDATION_ERROR);
|
|
.isEqualTo(ErrorCode.VALIDATION_ERROR);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /** 覆盖展望报告嵌套列表 Bean Validation 路径映射场景,应暴露请求 JSON 字段名并保留索引。 */
|
|
|
|
|
|
|
+ /** 覆盖展望报告大数组轻量校验场景,当 StudentWordsLatest 内部元素字段不满足约束时,入口只校验数组非空并继续创建。 */
|
|
|
@Test
|
|
@Test
|
|
|
- void createOutlookReportRejectsNestedStudentWordsLatestViolationWithApiFieldPath() throws Exception {
|
|
|
|
|
- ObjectNode invalidPayload = callerVocabularyPayload().deepCopy();
|
|
|
|
|
- ((ObjectNode) invalidPayload.withArray("StudentWordsLatest").get(0)).put("WordFrequency", 0);
|
|
|
|
|
|
|
+ void createOutlookReportAcceptsInvalidStudentWordsLatestElementsBecauseLargeArrayValidatesSizeOnly() throws Exception {
|
|
|
|
|
+ TestRepository repository = new TestRepository();
|
|
|
|
|
+ TestStorage storage = new TestStorage();
|
|
|
|
|
+ List<String> dispatchedReportIds = new ArrayList<>();
|
|
|
|
|
+ ObjectNode payload = callerVocabularyPayload().deepCopy();
|
|
|
|
|
+ ((ObjectNode) payload.withArray("StudentWordsLatest").get(0)).put("WordFrequency", 0);
|
|
|
|
|
+ ((ObjectNode) payload.withArray("StudentWordsLatest").get(1)).remove("Mastery");
|
|
|
|
|
+ payload.withArray("StudentWordsLatest").addNull();
|
|
|
|
|
|
|
|
- assertThatThrownBy(() -> service(new TestRepository(), reportId -> { }, new TestStorage())
|
|
|
|
|
- .createOutlookReport(invalidPayload))
|
|
|
|
|
- .isInstanceOf(BusinessException.class)
|
|
|
|
|
- .hasMessageContaining("展望报告参数校验失败")
|
|
|
|
|
- .hasMessageContaining("StudentWordsLatest[0].WordFrequency")
|
|
|
|
|
- .hasMessageContaining("必须大于等于 1")
|
|
|
|
|
- .extracting(exception -> ((BusinessException) exception).getErrorCode())
|
|
|
|
|
- .isEqualTo(ErrorCode.VALIDATION_ERROR);
|
|
|
|
|
|
|
+ var response = service(repository, dispatchedReportIds::add, storage).createOutlookReport(payload);
|
|
|
|
|
+
|
|
|
|
|
+ assertThat(response.reportId()).isNotBlank();
|
|
|
|
|
+ assertThat(repository.findById(response.reportId())).isPresent();
|
|
|
|
|
+ assertThat(dispatchedReportIds).containsExactly(response.reportId());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /** 覆盖展望报告直接列表元素约束路径映射场景,应隐藏 Bean Validation 内部 list element 片段。 */
|
|
|
|
|
|
|
+ /** 覆盖展望报告大数组轻量校验场景,当 TestPaperWordIdArray 元素不满足约束时,入口只校验数组非空并继续创建。 */
|
|
|
@Test
|
|
@Test
|
|
|
- void createOutlookReportRejectsDirectListElementViolationWithCleanApiFieldPath() throws Exception {
|
|
|
|
|
- ObjectNode invalidPayload = callerVocabularyPayload().deepCopy();
|
|
|
|
|
- invalidPayload.withArray("TestPaperWordIdArray").removeAll();
|
|
|
|
|
- invalidPayload.withArray("TestPaperWordIdArray").add(-1);
|
|
|
|
|
|
|
+ void createOutlookReportAcceptsInvalidTestPaperWordIdArrayElementsBecauseLargeArrayValidatesSizeOnly() throws Exception {
|
|
|
|
|
+ TestRepository repository = new TestRepository();
|
|
|
|
|
+ TestStorage storage = new TestStorage();
|
|
|
|
|
+ List<String> dispatchedReportIds = new ArrayList<>();
|
|
|
|
|
+ ObjectNode payload = callerVocabularyPayload().deepCopy();
|
|
|
|
|
+ payload.withArray("TestPaperWordIdArray").removeAll();
|
|
|
|
|
+ payload.withArray("TestPaperWordIdArray").add(-1);
|
|
|
|
|
+ payload.withArray("TestPaperWordIdArray").addNull();
|
|
|
|
|
|
|
|
- assertThatThrownBy(() -> service(new TestRepository(), reportId -> { }, new TestStorage())
|
|
|
|
|
- .createOutlookReport(invalidPayload))
|
|
|
|
|
- .isInstanceOf(BusinessException.class)
|
|
|
|
|
- .hasMessageContaining("展望报告参数校验失败")
|
|
|
|
|
- .hasMessageContaining("TestPaperWordIdArray[0]")
|
|
|
|
|
- .hasMessageNotContaining("<list element>")
|
|
|
|
|
- .hasMessageContaining("必须大于等于 0")
|
|
|
|
|
- .extracting(exception -> ((BusinessException) exception).getErrorCode())
|
|
|
|
|
- .isEqualTo(ErrorCode.VALIDATION_ERROR);
|
|
|
|
|
|
|
+ var response = service(repository, dispatchedReportIds::add, storage).createOutlookReport(payload);
|
|
|
|
|
+
|
|
|
|
|
+ assertThat(response.reportId()).isNotBlank();
|
|
|
|
|
+ assertThat(repository.findById(response.reportId())).isPresent();
|
|
|
|
|
+ assertThat(dispatchedReportIds).containsExactly(response.reportId());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/** 覆盖展望报告新词汇契约场景,当调用方不再传真题词数组但传 TestPaperUnMasterWordCount 时,应正常创建并分发。 */
|
|
/** 覆盖展望报告新词汇契约场景,当调用方不再传真题词数组但传 TestPaperUnMasterWordCount 时,应正常创建并分发。 */
|
|
@@ -351,13 +353,19 @@ class ExamSprintReportApplicationServiceTest {
|
|
|
assertCreateOutlookReportRejectsInvalidPayload(invalidPayload);
|
|
assertCreateOutlookReportRejectsInvalidPayload(invalidPayload);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /** 覆盖上游词汇报文明细含 null 元素的场景,当 StudentWordsLatest 中存在 null 时,应在保存前校验失败。 */
|
|
|
|
|
|
|
+ /** 覆盖上游词汇报文明细含 null 元素的场景,当 StudentWordsLatest 非空但包含 null 时,入口不递归校验元素。 */
|
|
|
@Test
|
|
@Test
|
|
|
- void createOutlookReportRejectsCallerVocabularyPayloadWithNullStudentWordLatest() throws Exception {
|
|
|
|
|
- ObjectNode invalidPayload = callerVocabularyPayload().deepCopy();
|
|
|
|
|
- ((com.fasterxml.jackson.databind.node.ArrayNode) invalidPayload.get("StudentWordsLatest")).addNull();
|
|
|
|
|
|
|
+ void createOutlookReportAcceptsCallerVocabularyPayloadWithNullStudentWordLatest() throws Exception {
|
|
|
|
|
+ TestRepository repository = new TestRepository();
|
|
|
|
|
+ List<String> dispatchedReportIds = new ArrayList<>();
|
|
|
|
|
+ ObjectNode payload = callerVocabularyPayload().deepCopy();
|
|
|
|
|
+ ((com.fasterxml.jackson.databind.node.ArrayNode) payload.get("StudentWordsLatest")).addNull();
|
|
|
|
|
|
|
|
- assertCreateOutlookReportRejectsInvalidPayload(invalidPayload);
|
|
|
|
|
|
|
+ var response = service(repository, dispatchedReportIds::add, new TestStorage()).createOutlookReport(payload);
|
|
|
|
|
+
|
|
|
|
|
+ assertThat(response.reportId()).isNotBlank();
|
|
|
|
|
+ assertThat(repository.findById(response.reportId())).isPresent();
|
|
|
|
|
+ assertThat(dispatchedReportIds).containsExactly(response.reportId());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/** 覆盖创建成果报告的调用方 PascalCase 报文场景,当提交有效 payload 时,应映射为领域内容并保存 ACHIEVEMENT 报告。 */
|
|
/** 覆盖创建成果报告的调用方 PascalCase 报文场景,当提交有效 payload 时,应映射为领域内容并保存 ACHIEVEMENT 报告。 */
|