关于 generate-cds-unit-test
此技能根据 CDS 实体生成使用 CDS Test Double Framework 的 ABAP Unit 测试类,面向需要验证 CDS 逻辑的 ABAP 开发者。它分析实体语义并生成测试代码,支持预览、写入和验证流程。
主要功能
- 01读取 CDS 定义、字段及依赖
- 02识别可测试的 CDS 语义
- 03生成 ABAP Unit 测试类
- 04支持代码检查、激活与测试
适用场景
- 01为包含计算或筛选的 CDS 实体编写单元测试
- 02为 CDS 重构建立回归测试
- 03检查关联、聚合和 CASE 逻辑
MCP 相关
技能通过 ARC-1 访问 SAP,并使用 mcp-sap-docs 查询 CDS Test Double Framework 和 ABAP Unit 文档。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ arc-mcp/ arc-1 --skill generate-cds-unit-test安装后在 Claude Code 中输入/generate-cds-unit-test确认已加载。
详细介绍
生成 CDS 单元测试
使用 CDS 测试替身框架,为 CDS 实体生成 ABAP Unit 测试类。
此技能通过结合 ARC-1(SAP 系统访问)和 mcp-sap-docs(文档和最佳实践),复现 SAP Joule 的“CDS 单元测试生成”功能。
智能默认值(静默应用,不要询问)
| 设置 | 默认值 | 原因 |
|---|---|---|
| 测试类名称 | ZCL_TEST_<entity_name> | 标准约定 |
| 包 | $TMP | 快速原型开发 |
| 测试范围 | 所有可测试语义 | 用户查看列表后可缩小范围 |
| 风险级别 | HARMLESS | CDS 测试替身不会修改真实数据 |
| 持续时间 | SHORT | 单元测试应快速运行 |
输入
用户提供 CDS 实体名称(例如,ZI_SALESORDER、ZC_TRAVEL)。
只需提供 CDS 实体名称。如果用户只提供实体名称,请应用智能默认值并立即继续。
用户也可以选择指定:
- 测试类名称(默认值:
ZCL_TEST_<entity_name>) - 包(默认值:
$TMP) - 传输请求(仅非
$TMP包需要)
第 1 步:收集 CDS 实体上下文
只需调用 3 次工具,即可读取 CDS 实体、其字段结构和所有依赖项。
1a. 读取 CDS DDL 源代码
SAPRead(type="DDLS", name="<entity_name>")
1b. 获取结构化字段列表
SAPRead(type="DDLS", name="<entity_name>", include="elements")
返回包含所有字段的格式化列表,其中包括键标记、别名、关联引用和表达式类型(计算、case、cast、coalesce)。使用此列表了解实体结构,无需解析原始 DDL。
1c. 获取依赖项上下文(表、视图、关联)
SAPContext(type="DDLS", name="<entity_name>")
自动从 CDS DDL 中提取所有数据源(FROM、JOIN)、关联、组合和投影基础。对于每个依赖项,都会通过类型回退(DDLS → TABL → STRU)获取完整源代码。由此可以了解:
- 底层表定义及字段类型(用于创建类型正确的测试数据)
- 其他 CDS 视图源(用于理解传递逻辑)
- 关联目标
对于更深层的依赖关系图(例如,消费视图 → 接口视图 → 表),请使用 depth=2:
SAPContext(type="DDLS", name="<entity_name>", depth=2)
1d. (可选)读取元数据扩展和行为定义
SAPRead(type="DDLX", name="<entity_name>")
SAPRead(type="BDEF", name="<entity_name>")
如果不存在 DDLX/BDEF,这些操作可能会失败——无需担心,跳过即可。只有实体具有 UI 注解或 RAP 行为时才需要读取。
第 2 步:分析 CDS 语义并提出测试用例
首选方式(SAP_BASIS 8.16+ — ABAP Platform 2025 / S/4HANA 2025):直接询问 SAP。 SAP 会分析实体并返回权威的可测试语义列表——这与 SAP Joule 的 CDS 单元测试生成所用的 CDS 测试替身框架引擎相同:
SAPDiagnose(action="cds_testcases", name="<entity_name>")
每条建议都包含可直接使用的 testMethod 名称、semanticType(NONE = 整个视图、CALCULATION、CAST、JOIN、CASE 等)、description,以及计算或强制转换场景中的 calculatedField。将此列表作为下文“输出给用户”部分的建议测试用例列表:这是 SAP 自身的分析结果,因此优先于手动解析 DDL。将每个 semanticType 映射到类别表,并将每个 testMethod 映射到第 4 步中的 FOR TESTING 方法。如果工具返回“requires SAP_BASIS 8.16+”消息(较旧版本 / NW 7.5x 不提供此端点),或者你想交叉检查覆盖范围,请使用下方的手动分析方式。
备用方式 / 交叉检查 — 自行分析 DDL。 分析你在第 1 步读取的 CDS DDL 源代码,并找出所有可测试语义。按类别分组:
要查找的语义类别
| 类别 | 在 DDL 中查找的内容 | 测试用例示例 |
|---|---|---|
| 计算 | 算术表达式(field1 * field2、field1 - field2) | 插入已知值,验证计算结果 |
| CASE 表达式 | case when ... then ... else ... end | 每个分支各设计一个测试 |
| 类型转换 | cast(field as abap.dec(15,2))、cast(field as abap.char(10)) | 插入值,验证转换结果 |
| WHERE 筛选 | where status = 'A' 或 where amount > 0 | 插入符合条件和不符合条件的行,验证仅显示符合条件的行 |
| HAVING 子句 | having sum(amount) > 1000 | 插入会触发和不会触发筛选条件的数据 |
| JOIN | inner join、left outer join、association | 在两个表中插入键匹配的数据;对于外连接,使用不匹配的键进行测试 |
| 聚合 | 使用 group by 的 sum()、count()、avg()、min()、max() | 插入多行,验证聚合结果 |
| 空值处理 | coalesce(field, 'default')、空值安全表达式 | 插入字段为空的行,验证默认值 |
| 参数 | with parameters p_param : type | 使用参数调用视图,验证筛选结果 |
| 货币/单位转换 | currency_conversion()、unit_conversion() | 插入转换数据,验证结果 |
| 字符串操作 | concat()、substring()、length() | 插入字符串值,验证输出 |
| 关联 | association [0..*] to ... | 在两侧插入数据,验证导航 |
向用户输出
将识别出的测试用例以编号列表形式呈现:
Identified test cases for ZI_SALESORDER:
1. [CALCULATION] test_net_amount_calculation — Verify net_amount = gross_amount - discount
2. [CASE] test_status_text_open — Verify status 'O' maps to 'Open'
3. [CASE] test_status_text_closed — Verify status 'C' maps to 'Closed'
4. [JOIN] test_customer_join — Verify customer data is correctly joined
5. [WHERE] test_active_orders_filter — Verify only active orders are returned
6. [NULL] test_description_coalesce — Verify null description gets default value
询问用户:“要生成哪些测试用例?(全部/指定编号/跳过哪些?)”
如果用户回答“全部”或未说明偏好,则生成全部用例。
步骤 3:获取 CDS 测试替身框架参考资料
使用 mcp-sap-docs 获取最新的 CDS 测试替身框架模式,确保生成的代码遵循 SAP 最佳实践。
search("CDS test double framework cl_cds_test_environment")
还要获取:
search("ABAP Unit cl_abap_unit_assert")
使用返回的文档来确定生成代码的模式。需要核实的关键内容:
cl_cds_test_environment=>create()的正确签名- 正确的
get_double()/insert()模式 - 正确的断言方法名称
步骤 4:生成测试类
按照以下结构生成完整的 ABAP 测试类:
模板
"! @testing <CDS_ENTITY_NAME>
CLASS <test_class_name> DEFINITION
PUBLIC FINAL
FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PUBLIC SECTION.
PROTECTED SECTION.
PRIVATE SECTION.
CLASS-DATA environment TYPE REF TO if_cds_test_environment.
CLASS-METHODS class_setup RAISING cx_static_check.
CLASS-METHODS class_teardown.
METHODS setup.
"! <description of test case 1>
METHODS <test_method_1> FOR TESTING RAISING cx_static_check.
"! <description of test case 2>
METHODS <test_method_2> FOR TESTING RAISING cx_static_check.
" ... one method per selected test case
ENDCLASS.
CLASS <test_class_name> IMPLEMENTATION.
METHOD class_setup.
environment = cl_cds_test_environment=>create( i_for_entity = '<CDS_ENTITY_NAME>' ).
ENDMETHOD.
METHOD class_teardown.
environment->destroy( ).
ENDMETHOD.
METHOD setup.
environment->clear_doubles( ).
ENDMETHOD.
METHOD <test_method_1>.
" Arrange — prepare test data for underlying tables
DATA lt_<table> TYPE STANDARD TABLE OF <underlying_table> WITH EMPTY KEY.
lt_<table> = VALUE #(
( <field1> = '<value1>' <field2> = '<value2>' ... )
).
environment->get_double( '<UNDERLYING_TABLE>' )->insert( lt_<table> ).
" Act — SELECT from the CDS entity under test
SELECT * FROM <cds_entity> INTO TABLE @DATA(lt_result).
" Assert — verify expected behavior
cl_abap_unit_assert=>assert_equals(
act = lines( lt_result )
exp = <expected_count>
msg = |Expected { <expected_count> } rows| ).
cl_abap_unit_assert=>assert_equals(
act = lt_result[ 1 ]-<field>
exp = '<expected_value>'
msg = '<assertion message>' ).
ENDMETHOD.
" ... more test methods
ENDCLASS.
测试数据生成规则
生成测试数据时,请遵循以下原则:
- 最少行数:使用尽可能少的行来测试该语义。通常每项测试使用 1~3 行。
- 直观的值:选择能轻松验证预期结果的值:
- 对于
gross - discount = net:使用 100.00 - 10.00 = 90.00,而不是 37.83 - 4.27 - 对于 CASE 分支:使用 CASE 表达式中的确切值
- 对于 WHERE 筛选:一行符合条件,另一行不符合
- 对于
- 类型正确:严格匹配 ABAP 类型:
- NUMC 字段使用
'001'(带前导零的字符串) - DEC/CURR 字段使用
'100.00' - DATS 字段使用
'20260101' - CUKY 字段使用
'EUR'
- NUMC 字段使用
- 填充键字段:始终填充键字段,即使测试不会直接检查这些字段
- 结果确定:绝不使用随机值或依赖日期的值
- 相互独立:每个测试方法都应自成一体(在 setup 中使用 clear_doubles 确保这一点)
命名约定
- 测试类:
ZCL_TEST_<ENTITY>或ZCL_<ENTITY>_TEST - 测试方法:
test_<semantic>_<detail>(例如,test_status_case_open、test_net_amount_calc) - 方法名使用 snake_case(ABAP 测试方法的约定)
- 方法名长度不超过 30 个字符
步骤 5:预览并确认
向用户展示生成的完整测试类源代码,并询问:
“这是生成的测试类。要在 SAP 系统上创建它吗?(是/先编辑/取消)”
如果用户需要修改,请先完成修改,再继续操作。
步骤 6:创建、激活并测试
6-pre. 对生成的代码进行 Lint 检查(可选)
编写之前,根据 Lint 规则验证生成的代码:
SAPLint(action="lint", source="<generated_source>", name="<test_class_name>")
继续之前,请修复所有 Lint 检查结果。启用预写入 Lint 验证后,也会自动运行(默认:开启)。
6a. 创建测试类
SAPWrite(action="create", type="CLAS", name="<test_class_name>", source="<generated_source>", package="<package>", transport="<transport>")
6b. 更新源代码(如果 create 仅生成框架)
SAPWrite(action="update", type="CLAS", name="<test_class_name>", source="<generated_source>", transport="<transport>")
6c. 激活测试类
SAPActivate(type="CLAS", name="<test_class_name>")
激活会返回结构化响应,其中包含详细的错误/警告信息(包括行号)。请利用这些信息准确定位问题。
6d. 运行单元测试
SAPDiagnose(action="unittest", type="CLAS", name="<test_class_name>")
6e. 报告结果
向用户展示:
- 通过/失败/跳过的测试数量
- 对于任何失败:断言消息以及失败的测试方法
- 对于任何失败:建议的修复方法
如果测试失败:
- 分析失败消息
- 判断问题出在测试数据、断言还是 CDS 逻辑
- 使用
SAPWrite(action="edit_method", ...)修复测试方法 - 重新激活并再次运行
错误处理
常见问题及修复方法
| 错误 | 原因 | 修复方法 |
|---|---|---|
CX_CDS_TEST_ENVIRONMENT 在 class_setup 期间出现 | 实体名称错误或未激活 | 验证实体名称,检查激活状态 |
| VALUE 构造器中的类型不匹配 | 测试数据中的字段类型错误 | 检查 DD03L 或表结构以确认正确类型 |
GET_DOUBLE 无法处理某个数据源 | 数据源名称不匹配 | 检查 CDS DDL 中准确的数据源名称(区分大小写!) |
| 断言失败且出现意外值 | 测试数据或预期结果错误 | 重新检查 CDS 逻辑,调整测试数据或断言 |
| 激活错误:“未找到测试关系” | @testing 注解指向了错误的实体 | 修复 "! @testing 注释中的实体名称 |
| 类已存在 | 测试类已创建 | 改用 SAPWrite(action="update", ...) |
说明
BTP 与本地部署的差异
- BTP:只能创建 Z*/Y* 类。无法通过 DD03L 查询标准 SAP 表。请使用已发布的 CDS 实体进行类型引用。
- 本地部署:可完全访问 DD03L、DD02L 中的字段目录。可查询 TADIR 以检查对象是否存在。
此 Skill 不会执行的操作
- 性能测试:CDS 测试替身用于逻辑测试,而非性能测试
- 授权测试:DCL/CDS 访问控制测试需要单独的模式
- 集成测试:此功能生成隔离的单元测试,而非端到端流程
- RAP 行为测试:对于验证、操作/确定逻辑,请改用 RAP BO 测试替身框架
何时使用此 Skill
- CDS 实体包含非平凡逻辑(计算、CASE、筛选、联接)时
- 用户希望以基础测试覆盖率作为起点时
- 重构 CDS 逻辑并希望添加回归测试时
- 不适用于仅重命名字段的简单投影 — 如果第 2 步的分析发现没有可测试语义(只有字段重命名,没有计算、CASE、WHERE、JOIN 或聚合),请提醒用户:“此 CDS 视图只是一个简单投影,不包含可测试逻辑。单元测试只能验证字段是否正确设置别名,价值有限。建议改为测试底层视图。”