kcode-pi 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +358 -0
- package/dist/cli/kcode.d.ts +15 -0
- package/dist/cli/kcode.js +153 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +7 -0
- package/docs/KCODE_DISTRIBUTION.md +91 -0
- package/extensions/kingdee-harness.ts +180 -0
- package/extensions/kingdee-header.ts +122 -0
- package/extensions/kingdee-tools.ts +379 -0
- package/knowledge/.backup/v1.0.0/version.json +10 -0
- package/knowledge/cangqiong/product-notes.md +15 -0
- package/knowledge/common/business-flows.md +115 -0
- package/knowledge/common/config-guides.md +110 -0
- package/knowledge/common/error-patterns.md +170 -0
- package/knowledge/common/implementation.md +144 -0
- package/knowledge/cosmic/hard-constraints.md +38 -0
- package/knowledge/cosmic/ksql-datafix.md +34 -0
- package/knowledge/cosmic/platform-baseline.md +32 -0
- package/knowledge/cosmic/plugin-decision-matrix.md +40 -0
- package/knowledge/cosmic/review-checklist.md +40 -0
- package/knowledge/cosmic/unittest.md +35 -0
- package/knowledge/enterprise/api-reference.md +186 -0
- package/knowledge/enterprise/code-patterns.md +217 -0
- package/knowledge/enterprise/plugin-lifecycle.md +188 -0
- package/knowledge/enterprise/tables.json +159 -0
- package/knowledge/flagship/api-reference.md +237 -0
- package/knowledge/flagship/code-patterns.md +246 -0
- package/knowledge/flagship/cosmic-platform-note.md +15 -0
- package/knowledge/flagship/plugin-lifecycle.md +248 -0
- package/knowledge/flagship/tables.json +159 -0
- package/knowledge/version.json +10 -0
- package/knowledge/xinghan/product-notes.md +15 -0
- package/package.json +71 -0
- package/prompts/kd-discuss.md +11 -0
- package/prompts/kd-execute.md +12 -0
- package/prompts/kd-plan.md +12 -0
- package/prompts/kd-ship.md +12 -0
- package/prompts/kd-spec.md +12 -0
- package/prompts/kd-verify.md +12 -0
- package/skills/kd-check/SKILL.md +26 -0
- package/skills/kd-cosmic-dev/SKILL.md +82 -0
- package/skills/kd-cosmic-review/SKILL.md +90 -0
- package/skills/kd-cosmic-unittest/SKILL.md +92 -0
- package/skills/kd-debug/SKILL.md +30 -0
- package/skills/kd-discuss/SKILL.md +24 -0
- package/skills/kd-execute/SKILL.md +22 -0
- package/skills/kd-gen/SKILL.md +34 -0
- package/skills/kd-ksql/SKILL.md +86 -0
- package/skills/kd-plan/SKILL.md +24 -0
- package/skills/kd-ship/SKILL.md +22 -0
- package/skills/kd-spec/SKILL.md +24 -0
- package/skills/kd-verify/SKILL.md +22 -0
- package/themes/kcode-dark.json +81 -0
- package/vendor/kingdee-skills/cosmic-unittest/SKILL.md +788 -0
- package/vendor/kingdee-skills/cosmic-unittest/author-cache.json +5 -0
- package/vendor/kingdee-skills/cosmic-unittest/cosmic-unittest-skill-overview.html +746 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/business-test.md +205 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/common-test.md +257 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/formplugin-test.md +560 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/op-plugin-test.md +231 -0
- package/vendor/kingdee-skills/cosmic-unittest/examples/validator-test.md +232 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/business-helper.md +184 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/common-module.md +355 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/convert-plugin.md +130 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/formplugin.md +235 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/op-plugin.md +226 -0
- package/vendor/kingdee-skills/cosmic-unittest/patterns/validator.md +206 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/SKILL.md +674 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/advanced-scenario-checklist.md +307 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/algox-performance-checklist.md +129 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/coding-standard-checklist.md +491 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/cosmic-api-checklist.md +285 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/data-access-checklist.md +261 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/data-transaction-checklist.md +390 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/domain-logic-checklist.md +295 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/form-plugin-checklist.md +508 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/infra-checklist.md +254 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/ksql-checklist.md +305 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/lifecycle-checklist.md +298 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/operation-plugin-checklist.md +442 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/test-mock-checklist.md +120 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/ui-performance-checklist.md +320 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/pattern-matcher.py +336 -0
- package/vendor/kingdee-skills/kingdee-cosmic-reviewer/scripts/review-score-calculator.py +121 -0
- package/vendor/kingdee-skills/ok-cosmic/CHANGELOG.md +295 -0
- package/vendor/kingdee-skills/ok-cosmic/README.md +460 -0
- package/vendor/kingdee-skills/ok-cosmic/SKILL.md +287 -0
- package/vendor/kingdee-skills/ok-cosmic/agents/openai.yaml +17 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/BatchImportPluginTemplate.java +93 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/BillPlugInTemplate.java +156 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ConvertPlugInTemplate.java +255 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/FormPluginTemplate.java +597 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/IWorkflowPluginTemplate.java +91 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ListPluginTemplate.java +194 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/OpPluginTemplate.java +201 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/OpenApiControllerTemplate.java +103 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/PrintPluginTemplate.java +95 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ReportFormPluginTemplate.java +257 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/ReportListDataPluginTemplate.java +70 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/StandardTreeListPluginTemplate.java +130 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/TaskTemplate.java +80 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/TreeListPluginTemplate.java +152 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/WriteBackPlugInTemplate.java +286 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/attachment/AttachmentUploadBindSample.java +93 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/botp/BotpTracePushSample.java +168 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/botp/SampleConvertPlugin.java +223 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/cache/SampleCacheUsage.java +218 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/concurrent/SampleThreadPoolBatch.java +156 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/data/DynamicObjectCrudSample.java +205 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/data/DynamicObjectOpsSample.java +100 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/BeforeOperationConfirmSample.java +217 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ConfirmDialogSample.java +131 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/EntryRowCalculateSample.java +116 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/F7FilterSample.java +134 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/GetAndSetValueSample.java +176 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/HyperlinkJumpSample.java +124 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/OpenBillModalSample.java +253 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ReturnParentDataSample.java +295 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/TreeControlSample.java +140 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/form/ViewControlOpsSample.java +132 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/list/ListPluginBasicSample.java +170 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/list/ListPreOpenFilterSample.java +68 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/message/MessageNotifySample.java +95 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/mq/SampleMQConsumer.java +198 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/mq/sample_mq.xml +15 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/operation/OpAddValidatorsSample.java +137 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/operation/OperationOptionBridgeSample.java +228 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/package-info.java +19 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/BaseDataQuerySample.java +194 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/BatchQuerySample.java +368 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/query/DataSetQueryStatSample.java +131 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportFormPlugin.java +179 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/report/SampleReportListDataPlugin.java +616 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/snippets-guide.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/task/ScheduleTaskSample.java +160 -0
- package/vendor/kingdee-skills/ok-cosmic/assets/snippets/workflow/SampleWorkflowPlugin.java +302 -0
- package/vendor/kingdee-skills/ok-cosmic/manifest.json +78 -0
- package/vendor/kingdee-skills/ok-cosmic/ok-cosmic-intro.html +903 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/attachment-api.md +114 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/botp-convert.md +98 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/dynamic-object.md +113 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/entity-metadata.md +123 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/event-lifecycle.md +184 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/flex-prop.md +114 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/form-utils.md +133 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/operate-chain.md +159 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/plugin-base.md +218 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/query-dataset.md +149 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/request-context.md +88 -0
- package/vendor/kingdee-skills/ok-cosmic/references/adv/view-handler.md +157 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-bill.md +76 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-botp.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-form.md +165 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-import.md +69 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-list.md +227 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-openapi.md +112 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-operation.md +135 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-print.md +65 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-report-data.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-report-form.md +90 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-task.md +62 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-tree-list.md +71 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-workflow.md +82 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/plugin/plugin-writeback.md +71 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-algo.md +67 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-cache.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-dynamic-model-svc.md +82 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-dynamic-object.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-entity-model.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-exception.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-file.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-id.md +47 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-lock.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-log.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-network-control.md +70 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-orm-access.md +78 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-request-context.md +62 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-threadpool.md +63 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-tx.md +64 -0
- package/vendor/kingdee-skills/ok-cosmic/references/base/sdk/sdk-utils.md +67 -0
- package/vendor/kingdee-skills/ok-cosmic/requirements.txt +2 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/a-layer-rules.json +24 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/anti-patterns.md +48 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/cheat-sheet.md +256 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/coding-preferences.md +140 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/constraints.md +61 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/decision-matrix.md +222 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/intent-routing.md +94 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/platform-baseline.md +69 -0
- package/vendor/kingdee-skills/ok-cosmic/rules/post-check.md +109 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/config_loader.py +204 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-api-knowledge.py +910 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-basedata-query.py +359 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-config-check.py +181 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-extpoints-query.py +389 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-form-metadata.py +856 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-check.py +262 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/cosmic-post-lint.py +293 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/__init__.py +2 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/base.py +393 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/resource_check.py +176 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/scene_check.py +375 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/style_check.py +434 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/lint/verify_check.py +36 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/route_client.py +186 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/script_utils.py +40 -0
- package/vendor/kingdee-skills/ok-cosmic/scripts/sqlite_cache.py +142 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-commons.jar +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/cuslib/kd-cd-cosmic-features.jar +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/ok-cosmic-docs.db +0 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/ok-cosmic.json +13 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup-mac.sh +18 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup-windows.bat +53 -0
- package/vendor/kingdee-skills/ok-cosmic/setup/setup.jar +0 -0
- package/vendor/kingdee-skills/ok-ksql/SKILL.md +81 -0
- package/vendor/kingdee-skills/ok-ksql/agents/openai.yaml +7 -0
- package/vendor/kingdee-skills/ok-ksql/manifest.json +14 -0
- package/vendor/kingdee-skills/ok-ksql/references/ksql-datafix.md +452 -0
- package/vendor/kingdee-skills/ok-ksql/scripts/ksql_lint.py +363 -0
package/vendor/kingdee-skills/kingdee-cosmic-reviewer/references/operation-plugin-checklist.md
ADDED
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
# 操作插件场景检查表
|
|
2
|
+
|
|
3
|
+
## 🔴 P0 级问题
|
|
4
|
+
|
|
5
|
+
### 1. onPreparePropertys 未声明使用字段
|
|
6
|
+
**检查点**:
|
|
7
|
+
- 操作插件中 `beginOperationTransaction` / `endOperationTransaction` 等方法使用了实体字段,但 `onPreparePropertys` 未通过 `e.getFieldKeys().add()` 声明?
|
|
8
|
+
- 校验器 `validate` 中使用了字段,但关联的 `preparePropertys` 未返回对应字段?
|
|
9
|
+
|
|
10
|
+
**风险**: 未声明的字段在操作执行时不会被预加载,运行时值为 null,导致业务逻辑静默失效
|
|
11
|
+
|
|
12
|
+
**修正方案**:
|
|
13
|
+
```java
|
|
14
|
+
// ❌ 错误写法 - 使用了字段但未声明
|
|
15
|
+
@Override
|
|
16
|
+
public void beginOperationTransaction(BeginOperationTransactionArgs e) {
|
|
17
|
+
for (DynamicObject obj : e.getDataEntities()) {
|
|
18
|
+
String status = obj.getString("billstatus"); // 未声明,可能为 null
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// ✅ 正确写法 - 在 onPreparePropertys 中声明
|
|
23
|
+
@Override
|
|
24
|
+
public void onPreparePropertys(PreparePropertysEventArgs e) {
|
|
25
|
+
super.onPreparePropertys(e);
|
|
26
|
+
e.getFieldKeys().add("billstatus");
|
|
27
|
+
e.getFieldKeys().add("entryentity.material");
|
|
28
|
+
e.getFieldKeys().add("entryentity.qty");
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
### 2. beforeExecuteOperationTransaction 中独立保存
|
|
35
|
+
**检查点**:
|
|
36
|
+
- `beforeExecuteOperationTransaction` 中是否调用了 `SaveServiceHelper.save()` 或 `SaveServiceHelper.update()`?
|
|
37
|
+
- 是否在事务钩子内创建了独立的保存操作?
|
|
38
|
+
|
|
39
|
+
**风险**: 事务钩子内独立保存会脱离当前事务,导致数据不一致;若主事务回滚,独立保存的数据不会回滚
|
|
40
|
+
|
|
41
|
+
**修正方案**:
|
|
42
|
+
```java
|
|
43
|
+
// ❌ 错误写法 - 事务钩子内独立保存
|
|
44
|
+
@Override
|
|
45
|
+
public void beforeExecuteOperationTransaction(BeforeOperationArgs e) {
|
|
46
|
+
for (DynamicObject obj : e.getDataEntities()) {
|
|
47
|
+
obj.set("amount", calculateAmount(obj));
|
|
48
|
+
SaveServiceHelper.save(new DynamicObject[]{obj}); // 脱离事务!
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ✅ 正确写法 - 直接修改数据实体,由框架统一保存
|
|
53
|
+
@Override
|
|
54
|
+
public void beforeExecuteOperationTransaction(BeforeOperationArgs e) {
|
|
55
|
+
for (DynamicObject obj : e.getDataEntities()) {
|
|
56
|
+
obj.set("amount", calculateAmount(obj));
|
|
57
|
+
// 不需要手动保存,框架会在事务内统一处理
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### 3. 自定义校验器字段未声明
|
|
65
|
+
**检查点**:
|
|
66
|
+
- 自定义校验器(继承 `AbstractValidator`)的 `validate` 方法中使用了字段,但 `preparePropertys` 未返回?
|
|
67
|
+
- 关联的操作插件 `onPreparePropertys` 是否也声明了校验器需要的字段?
|
|
68
|
+
|
|
69
|
+
**风险**: 校验器拿到的字段值为默认值(null/0),校验逻辑基于错误数据静默通过
|
|
70
|
+
|
|
71
|
+
**修正方案**:
|
|
72
|
+
```java
|
|
73
|
+
// ❌ 错误写法 - 校验器未声明字段
|
|
74
|
+
public class MyValidator extends AbstractValidator {
|
|
75
|
+
@Override
|
|
76
|
+
public void validate() {
|
|
77
|
+
for (ExtendedDataEntity entity : getDataEntities()) {
|
|
78
|
+
BigDecimal qty = entity.getDataEntity().getBigDecimal("qty"); // 未声明
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ✅ 正确写法
|
|
84
|
+
public class MyValidator extends AbstractValidator {
|
|
85
|
+
@Override
|
|
86
|
+
public Set<String> preparePropertys() {
|
|
87
|
+
Set<String> fields = super.preparePropertys();
|
|
88
|
+
if (fields == null) {
|
|
89
|
+
fields = new HashSet<>();
|
|
90
|
+
}
|
|
91
|
+
fields.add("qty");
|
|
92
|
+
fields.add("entryentity.material");
|
|
93
|
+
return fields;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@Override
|
|
97
|
+
public void validate() {
|
|
98
|
+
for (ExtendedDataEntity entity : getDataEntities()) {
|
|
99
|
+
BigDecimal qty = entity.getDataEntity().getBigDecimal("qty");
|
|
100
|
+
if (qty == null || qty.compareTo(BigDecimal.ZERO) <= 0) {
|
|
101
|
+
addErrorMessage(entity, "数量必须大于零");
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
### 4. 交互式操作死循环(KDInteractionException)
|
|
111
|
+
**检查点**:
|
|
112
|
+
- 抛出 `KDInteractionException` 前是否先检查了交互确认结果(`InteractionConfirmResult`)?
|
|
113
|
+
- 交互标识(sponsor)是否唯一且固定?
|
|
114
|
+
|
|
115
|
+
**风险**: 用户确认后再次进入操作,再次抛出交互异常,形成死循环
|
|
116
|
+
|
|
117
|
+
**修正方案**:
|
|
118
|
+
```java
|
|
119
|
+
// ❌ 错误写法 - 未检查回调,死循环
|
|
120
|
+
@Override
|
|
121
|
+
public void beforeExecuteOperationTransaction(BeforeOperationArgs e) {
|
|
122
|
+
throw new KDInteractionException("sponsor", ctx); // 每次都抛!
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ✅ 正确写法 - 先检查是否为回调
|
|
126
|
+
private static final String SPONSOR = "com.xxx.MyPlugin";
|
|
127
|
+
|
|
128
|
+
@Override
|
|
129
|
+
public void beforeExecuteOperationTransaction(BeforeOperationArgs e) {
|
|
130
|
+
String confirmStr = this.getOption().getVariableValue(
|
|
131
|
+
OperateOptionConst.INTERACTIONCONFIRMRESULT, "");
|
|
132
|
+
InteractionConfirmResult confirmResult =
|
|
133
|
+
InteractionConfirmResult.fromJsonString(confirmStr);
|
|
134
|
+
if (confirmResult.getResults().containsKey(SPONSOR)) {
|
|
135
|
+
MessageBoxResult result = MessageBoxResult.valueOf(
|
|
136
|
+
confirmResult.getResults().get(SPONSOR));
|
|
137
|
+
if (result == MessageBoxResult.Yes) {
|
|
138
|
+
return; // 用户已确认,继续执行
|
|
139
|
+
} else {
|
|
140
|
+
e.cancel = true;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// 首次进入,抛出交互
|
|
145
|
+
InteractionContext ctx = new InteractionContext();
|
|
146
|
+
ctx.setSimpleMessage("确认继续?");
|
|
147
|
+
throw new KDInteractionException(SPONSOR, ctx);
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 🟠 P1 级问题
|
|
154
|
+
|
|
155
|
+
### 5. OperationResult 未检查即使用
|
|
156
|
+
**检查点**:
|
|
157
|
+
- 调用 `OperationServiceHelper.executeOperate()` 后是否检查了 `OperationResult.isSuccess()`?
|
|
158
|
+
- 操作失败时是否有错误处理逻辑?
|
|
159
|
+
|
|
160
|
+
**风险**: 操作失败但代码继续执行后续逻辑,导致数据不一致
|
|
161
|
+
|
|
162
|
+
**修正方案**:
|
|
163
|
+
```java
|
|
164
|
+
// ❌ 错误写法 - 未检查操作结果
|
|
165
|
+
OperationServiceHelper.executeOperate("submit", "demo_bill", ids, option);
|
|
166
|
+
// 直接执行后续逻辑...
|
|
167
|
+
|
|
168
|
+
// ✅ 正确写法
|
|
169
|
+
OperationResult result = OperationServiceHelper.executeOperate(
|
|
170
|
+
"submit", "demo_bill", ids, option);
|
|
171
|
+
if (!result.isSuccess()) {
|
|
172
|
+
String errorMsg = result.getAllErrorInfo();
|
|
173
|
+
logger.error("提交操作失败: {}", errorMsg);
|
|
174
|
+
throw new KDException(errorMsg);
|
|
175
|
+
}
|
|
176
|
+
Object[] successIds = result.getSuccessPkIds().toArray();
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
### 6. 操作错误提示级别不当
|
|
182
|
+
**检查点**:
|
|
183
|
+
- 校验器中使用 `addErrorMessage` 时是否区分了错误级别(Error/Warning)?
|
|
184
|
+
- Warning 级别的提示是否允许用户忽略继续?
|
|
185
|
+
|
|
186
|
+
**风险**: 所有问题都用 Error 级别会阻断操作;都用 Warning 级别则无法阻止严重问题
|
|
187
|
+
|
|
188
|
+
**修正方案**:
|
|
189
|
+
```java
|
|
190
|
+
// ✅ 正确写法 - 区分错误级别
|
|
191
|
+
@Override
|
|
192
|
+
public void validate() {
|
|
193
|
+
for (ExtendedDataEntity entity : getDataEntities()) {
|
|
194
|
+
BigDecimal qty = entity.getDataEntity().getBigDecimal("qty");
|
|
195
|
+
if (qty == null || qty.compareTo(BigDecimal.ZERO) <= 0) {
|
|
196
|
+
// Error 级别 - 阻断操作
|
|
197
|
+
addErrorMessage(entity, "数量必须大于零");
|
|
198
|
+
}
|
|
199
|
+
if (qty != null && qty.compareTo(new BigDecimal("10000")) > 0) {
|
|
200
|
+
// Warning 级别 - 允许用户忽略
|
|
201
|
+
addMessage(entity, "数量超过10000,请确认是否正确",
|
|
202
|
+
ErrorLevel.Warning);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
### 7. afterExecuteOperationTransaction 误用 getOperationResult
|
|
211
|
+
**检查点**:
|
|
212
|
+
- `afterExecuteOperationTransaction` 的参数类型是 `AfterOperationArgs`,是否错误调用了 `getOperationResult()`?
|
|
213
|
+
|
|
214
|
+
**风险**: `AfterOperationArgs` 没有 `getOperationResult()` 方法,编译通过但运行时报错
|
|
215
|
+
|
|
216
|
+
**修正方案**:
|
|
217
|
+
```java
|
|
218
|
+
// ❌ 错误写法 - AfterOperationArgs 无此方法
|
|
219
|
+
@Override
|
|
220
|
+
public void afterExecuteOperationTransaction(AfterOperationArgs e) {
|
|
221
|
+
e.getOperationResult(); // 方法不存在!
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ✅ 正确写法 - 使用 AfterOperationArgs 提供的方法
|
|
225
|
+
@Override
|
|
226
|
+
public void afterExecuteOperationTransaction(AfterOperationArgs e) {
|
|
227
|
+
DynamicObject[] entities = e.getDataEntities();
|
|
228
|
+
for (DynamicObject entity : entities) {
|
|
229
|
+
// 直接处理数据实体
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
### 8. 操作事件时序错误
|
|
237
|
+
**检查点**:
|
|
238
|
+
- 数据修改是否放在了正确的事件中?
|
|
239
|
+
- `endOperationTransaction` 中是否执行了应在 `beginOperationTransaction` 中完成的逻辑?
|
|
240
|
+
|
|
241
|
+
**风险**: 事件时序错误导致数据修改不在事务内,或修改被后续逻辑覆盖
|
|
242
|
+
|
|
243
|
+
**事件时序说明**:
|
|
244
|
+
```
|
|
245
|
+
onPreparePropertys → onAddValidators → validate
|
|
246
|
+
→ beforeExecuteOperationTransaction(事务开始前,可取消操作)
|
|
247
|
+
→ beginOperationTransaction(事务内,修改数据实体)
|
|
248
|
+
→ endOperationTransaction(事务内,后置处理如写日志)
|
|
249
|
+
→ afterExecuteOperationTransaction(事务提交后,不可回滚)
|
|
250
|
+
→ rollbackOperation(事务回滚时触发)
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**修正方案**:
|
|
254
|
+
```java
|
|
255
|
+
// ❌ 错误写法 - 在事务提交后修改数据
|
|
256
|
+
@Override
|
|
257
|
+
public void afterExecuteOperationTransaction(AfterOperationArgs e) {
|
|
258
|
+
for (DynamicObject obj : e.getDataEntities()) {
|
|
259
|
+
obj.set("status", "C"); // 事务已提交,修改不会被保存!
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// ✅ 正确写法 - 在事务内修改数据
|
|
264
|
+
@Override
|
|
265
|
+
public void beginOperationTransaction(BeginOperationTransactionArgs e) {
|
|
266
|
+
for (DynamicObject obj : e.getDataEntities()) {
|
|
267
|
+
obj.set("status", "C"); // 事务内修改,会被统一提交
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
### 9. 后台调用操作未设置 IGNOREINTERACTION
|
|
275
|
+
**检查点**:
|
|
276
|
+
- 后台代码(非表单触发)调用 `OperationServiceHelper.executeOperate()` 时,操作插件可能抛出 `KDInteractionException`,是否设置了 `IGNOREINTERACTION`?
|
|
277
|
+
|
|
278
|
+
**风险**: 后台无法弹出交互对话框,操作会失败且不重试
|
|
279
|
+
|
|
280
|
+
**修正方案**:
|
|
281
|
+
```java
|
|
282
|
+
// ❌ 错误写法 - 后台调用未忽略交互
|
|
283
|
+
OperateOption option = OperateOption.create();
|
|
284
|
+
OperationServiceHelper.executeOperate("submit", "demo_bill", ids, option);
|
|
285
|
+
|
|
286
|
+
// ✅ 正确写法 - 后台调用忽略交互
|
|
287
|
+
OperateOption option = OperateOption.create();
|
|
288
|
+
option.setVariableValue(OperateOptionConst.IGNOREINTERACTION, String.valueOf(true));
|
|
289
|
+
option.setVariableValue(OperateOptionConst.IGNOREWARN, String.valueOf(true));
|
|
290
|
+
OperationServiceHelper.executeOperate("submit", "demo_bill", ids, option);
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## 🟡 P2 级问题
|
|
296
|
+
|
|
297
|
+
### 10. 操作自定义参数命名冲突
|
|
298
|
+
**检查点**:
|
|
299
|
+
- `OperateOption.setVariableValue()` 的 key 是否使用了过于简单的名称(如 "flag"、"type")?
|
|
300
|
+
|
|
301
|
+
**风险**: 与其他插件或框架内置参数冲突,导致参数被覆盖
|
|
302
|
+
|
|
303
|
+
**修正方案**:
|
|
304
|
+
```java
|
|
305
|
+
// ❌ 错误写法 - 参数名过于简单
|
|
306
|
+
option.setVariableValue("flag", "true");
|
|
307
|
+
|
|
308
|
+
// ✅ 正确写法 - 带业务域前缀
|
|
309
|
+
option.setVariableValue("scmc_ccm_skipValidation", "true");
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
### 11. 操作内置服务与操作插件混淆
|
|
315
|
+
**检查点**:
|
|
316
|
+
- 通用性强的操作逻辑是否仍写在操作插件中而非操作内置服务?
|
|
317
|
+
- 操作内置服务(`AbstractOpBizRuleAction`)是否正确使用了 `getBizRule()` 获取配置参数?
|
|
318
|
+
|
|
319
|
+
**风险**: 通用逻辑写在操作插件中无法复用,每个操作都需要重复编写
|
|
320
|
+
|
|
321
|
+
**建议**: 将通用操作逻辑(如写日志、更新状态)抽象为操作内置服务,通过配置绑定到多个操作上复用
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
### 12. endOperationTransaction 中触发其他操作
|
|
326
|
+
**检查点**:
|
|
327
|
+
- `endOperationTransaction` 中是否调用了 `OperationServiceHelper.executeOperate()` 触发另一个操作?
|
|
328
|
+
- 被触发的操作是否会再次触发当前操作形成递归?
|
|
329
|
+
|
|
330
|
+
**风险**: 操作链形成循环调用,事务嵌套过深导致死锁或栈溢出
|
|
331
|
+
|
|
332
|
+
**修正方案**:
|
|
333
|
+
```java
|
|
334
|
+
// ❌ 错误写法 - 事务内触发其他操作
|
|
335
|
+
@Override
|
|
336
|
+
public void endOperationTransaction(EndOperationTransactionArgs e) {
|
|
337
|
+
for (DynamicObject obj : e.getDataEntities()) {
|
|
338
|
+
Object[] ids = new Object[]{obj.getLong("id")};
|
|
339
|
+
// 事务内触发新操作,可能导致事务嵌套
|
|
340
|
+
OperationServiceHelper.executeOperate("submit", "demo_bill", ids);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// ✅ 正确写法 - 使用 afterExecuteOperationTransaction(事务提交后)
|
|
345
|
+
@Override
|
|
346
|
+
public void afterExecuteOperationTransaction(AfterOperationArgs e) {
|
|
347
|
+
for (DynamicObject obj : e.getDataEntities()) {
|
|
348
|
+
Object[] ids = new Object[]{obj.getLong("id")};
|
|
349
|
+
OperateOption option = OperateOption.create();
|
|
350
|
+
option.setVariableValue(OperateOptionConst.IGNOREINTERACTION, "true");
|
|
351
|
+
OperationServiceHelper.executeOperate("submit", "demo_bill", ids, option);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
### 13. 批量操作数据量过大未分批
|
|
359
|
+
**检查点**:
|
|
360
|
+
- 操作插件处理的数据量是否可能超过 1000 条?
|
|
361
|
+
- 是否在操作插件内部做了分批处理?
|
|
362
|
+
|
|
363
|
+
**风险**: 单次操作数据量过大,事务过长导致数据库锁等待超时
|
|
364
|
+
|
|
365
|
+
**修正方案**:
|
|
366
|
+
```java
|
|
367
|
+
// ❌ 错误写法 - 一次性处理所有数据
|
|
368
|
+
@Override
|
|
369
|
+
public void beginOperationTransaction(BeginOperationTransactionArgs e) {
|
|
370
|
+
for (DynamicObject obj : e.getDataEntities()) {
|
|
371
|
+
// 如果有 10000 条数据,全在一个事务内处理
|
|
372
|
+
processData(obj);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// ✅ 正确写法 - 操作层面分批(调用方控制)
|
|
377
|
+
// 在调用方分批提交
|
|
378
|
+
int batchSize = 500;
|
|
379
|
+
List<Object> allIds = getAllIds();
|
|
380
|
+
for (int i = 0; i < allIds.size(); i += batchSize) {
|
|
381
|
+
List<Object> batchIds = allIds.subList(i, Math.min(i + batchSize, allIds.size()));
|
|
382
|
+
OperationServiceHelper.executeOperate("save", entityName,
|
|
383
|
+
batchIds.toArray());
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
### 14. rollbackOperation 中执行数据库写操作
|
|
390
|
+
**检查点**:
|
|
391
|
+
- `rollbackOperation` 回调中是否执行了 `SaveServiceHelper.save()` 或其他写数据库操作?
|
|
392
|
+
- 回滚处理中是否尝试记录日志到数据库?
|
|
393
|
+
|
|
394
|
+
**风险**: 事务回滚后再执行写操作可能被一起回滚,或导致新的异常覆盖原始异常
|
|
395
|
+
|
|
396
|
+
**修正方案**:
|
|
397
|
+
```java
|
|
398
|
+
// ❌ 错误写法 - 回滚中写数据库
|
|
399
|
+
@Override
|
|
400
|
+
public void rollbackOperation(RollbackOperationArgs e) {
|
|
401
|
+
DynamicObject log = new DynamicObject();
|
|
402
|
+
log.set("message", "操作失败: " + e.getException().getMessage());
|
|
403
|
+
SaveServiceHelper.save(new DynamicObject[]{log}); // 可能也被回滚!
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// ✅ 正确写法 - 回滚中只记录内存日志
|
|
407
|
+
@Override
|
|
408
|
+
public void rollbackOperation(RollbackOperationArgs e) {
|
|
409
|
+
logger.error("操作回滚,原因: {}", e.getException().getMessage(), e.getException());
|
|
410
|
+
// 如果需要持久化日志,使用异步方式在事务外执行
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
### 15. 多个操作插件执行顺序依赖
|
|
417
|
+
**检查点**:
|
|
418
|
+
- 同一操作绑定了多个操作插件时,是否存在执行顺序依赖?
|
|
419
|
+
- 插件之间是否通过 `OperateOption` 传递状态数据?
|
|
420
|
+
|
|
421
|
+
**风险**: 插件执行顺序不确定,依赖特定顺序的逻辑可能在不同环境下表现不一致
|
|
422
|
+
|
|
423
|
+
**修正方案**:
|
|
424
|
+
```java
|
|
425
|
+
// ❌ 错误写法 - 插件A设置标记,插件B依赖该标记
|
|
426
|
+
// PluginA:
|
|
427
|
+
@Override
|
|
428
|
+
public void beginOperationTransaction(BeginOperationTransactionArgs e) {
|
|
429
|
+
this.getOption().setVariableValue("pluginA_done", "true");
|
|
430
|
+
}
|
|
431
|
+
// PluginB:
|
|
432
|
+
@Override
|
|
433
|
+
public void beginOperationTransaction(BeginOperationTransactionArgs e) {
|
|
434
|
+
String flag = this.getOption().getVariableValue("pluginA_done", "");
|
|
435
|
+
if (!"true".equals(flag)) {
|
|
436
|
+
return; // 假设 A 先执行,但顺序不保证!
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// ✅ 正确写法 - 合并为一个插件,或使用操作链(前置操作 → 后置操作)
|
|
441
|
+
// 将有依赖关系的逻辑放在同一个插件中,通过方法拆分保持清晰
|
|
442
|
+
```
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# 单元测试 Mock 策略检查表
|
|
2
|
+
|
|
3
|
+
## 🔴 P0 级问题
|
|
4
|
+
|
|
5
|
+
### 1. 静态方法 Mock 未隔离
|
|
6
|
+
**检查点**:
|
|
7
|
+
- 是否使用 `MockedStatic` 但未用 try-with-resources?
|
|
8
|
+
- 静态 Mock 是否正确关闭?
|
|
9
|
+
|
|
10
|
+
**风险**: 测试污染,Mock 泄漏到其他测试
|
|
11
|
+
|
|
12
|
+
**修正方案**:
|
|
13
|
+
```java
|
|
14
|
+
// ❌ 错误写法 - Mock 未隔离
|
|
15
|
+
MockedStatic<BusinessDataServiceHelper> mock = mockStatic(BusinessDataServiceHelper.class);
|
|
16
|
+
mock.when(() -> BusinessDataServiceHelper.loadSingle(...)).thenReturn(obj);
|
|
17
|
+
// mock 未关闭!
|
|
18
|
+
|
|
19
|
+
// ✅ 正确写法 - try-with-resources
|
|
20
|
+
try (MockedStatic<BusinessDataServiceHelper> mock = mockStatic(BusinessDataServiceHelper.class)) {
|
|
21
|
+
mock.when(() -> BusinessDataServiceHelper.loadSingle(...)).thenReturn(obj);
|
|
22
|
+
// 测试代码
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
### 2. 可变参数重载匹配错误
|
|
29
|
+
**检查点**:
|
|
30
|
+
- `any()` 是否未强转?
|
|
31
|
+
- `eq()` 匹配是否正确?
|
|
32
|
+
|
|
33
|
+
**风险**: Mock 不生效,测试失败
|
|
34
|
+
|
|
35
|
+
**修正方案**:
|
|
36
|
+
```java
|
|
37
|
+
// ❌ 错误写法
|
|
38
|
+
when(service.method(any())).thenReturn(result); // any() 可能匹配错误
|
|
39
|
+
|
|
40
|
+
// ✅ 正确写法 - 明确类型
|
|
41
|
+
when(service.method(any(String.class))).thenReturn(result);
|
|
42
|
+
when(service.method(any(Long.class))).thenReturn(result);
|
|
43
|
+
when(service.method(eq("specific"))).thenReturn(result);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 🟠 P1 级问题
|
|
49
|
+
|
|
50
|
+
### 3. 测试数据未清理
|
|
51
|
+
**检查点**:
|
|
52
|
+
- 测试是否创建了数据但未清理?
|
|
53
|
+
- 是否使用 `@BeforeEach`/`@AfterEach` 管理数据?
|
|
54
|
+
|
|
55
|
+
**修正方案**:
|
|
56
|
+
```java
|
|
57
|
+
// ✅ 使用生命周期管理
|
|
58
|
+
@AfterEach
|
|
59
|
+
public void cleanup() {
|
|
60
|
+
// 清理测试数据
|
|
61
|
+
TestDataServiceHelper.deleteTestData(billIds);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
### 4. Mock 返回值不一致
|
|
68
|
+
**检查点**:
|
|
69
|
+
- Mock 返回值是否符合业务逻辑?
|
|
70
|
+
- 是否 Mock 了所有必要的方法?
|
|
71
|
+
|
|
72
|
+
**修正方案**:
|
|
73
|
+
```java
|
|
74
|
+
// ❌ 错误写法 - 返回 null
|
|
75
|
+
when(obj.getString("field")).thenReturn(null);
|
|
76
|
+
|
|
77
|
+
// ✅ 正确写法 - 返回合理值
|
|
78
|
+
when(obj.getString("field")).thenReturn("expectedValue");
|
|
79
|
+
when(obj.getBigDecimal("amount")).thenReturn(BigDecimal.valueOf(100));
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 🟡 P2 级问题
|
|
85
|
+
|
|
86
|
+
### 5. 测试命名不规范
|
|
87
|
+
**检查点**:
|
|
88
|
+
- 测试方法名是否清晰描述测试场景?
|
|
89
|
+
|
|
90
|
+
**修正方案**:
|
|
91
|
+
```java
|
|
92
|
+
// ❌ 错误写法
|
|
93
|
+
@Test
|
|
94
|
+
public void test1() { }
|
|
95
|
+
|
|
96
|
+
// ✅ 正确写法
|
|
97
|
+
@Test
|
|
98
|
+
public void shouldReturnErrorWhenAmountIsNegative() { }
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### 6. 断言不充分
|
|
104
|
+
**检查点**:
|
|
105
|
+
- 是否只验证了返回值,未验证副作用?
|
|
106
|
+
|
|
107
|
+
**修正方案**:
|
|
108
|
+
```java
|
|
109
|
+
// ✅ 完整断言
|
|
110
|
+
@Test
|
|
111
|
+
public void shouldSaveDataCorrectly() {
|
|
112
|
+
// when
|
|
113
|
+
service.save(data);
|
|
114
|
+
|
|
115
|
+
// then
|
|
116
|
+
verify(repository).save(data);
|
|
117
|
+
assertThat(data.getId()).isNotNull();
|
|
118
|
+
assertThat(data.getCreateTime()).isNotNull();
|
|
119
|
+
}
|
|
120
|
+
```
|