abapgit-agent 1.5.0 → 1.6.1

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.
Files changed (119) hide show
  1. package/README.md +1 -0
  2. package/abap/guidelines/00_index.md +36 -0
  3. package/abap/guidelines/01_sql.md +88 -0
  4. package/abap/guidelines/02_exceptions.md +176 -0
  5. package/abap/guidelines/03_testing.md +269 -0
  6. package/abap/guidelines/04_cds.md +136 -0
  7. package/abap/guidelines/05_classes.md +58 -0
  8. package/abap/guidelines/06_objects.md +110 -0
  9. package/abap/guidelines/07_json.md +24 -0
  10. package/abap/guidelines/08_abapgit.md +222 -0
  11. package/abap/guidelines/09_unit_testable_code.md +568 -0
  12. package/bin/abapgit-agent +513 -38
  13. package/bin/abgagt +24 -0
  14. package/package.json +8 -2
  15. package/src/abap-client.js +65 -2
  16. package/src/agent.js +57 -3
  17. package/src/config.js +1 -1
  18. package/src/ref-search.js +1037 -0
  19. package/.abapGitAgent.example +0 -11
  20. package/.github/workflows/release.yml +0 -60
  21. package/API.md +0 -710
  22. package/CLAUDE.md +0 -1058
  23. package/CLAUDE_MEM.md +0 -88
  24. package/ERROR_HANDLING.md +0 -30
  25. package/INSTALL.md +0 -155
  26. package/RELEASE_NOTES.md +0 -143
  27. package/abap/CLAUDE.md +0 -1010
  28. package/abap/copilot-instructions.md +0 -79
  29. package/abap/package.devc.xml +0 -10
  30. package/abap/zcl_abgagt_agent.clas.abap +0 -420
  31. package/abap/zcl_abgagt_agent.clas.xml +0 -15
  32. package/abap/zcl_abgagt_cmd_factory.clas.abap +0 -48
  33. package/abap/zcl_abgagt_cmd_factory.clas.xml +0 -15
  34. package/abap/zcl_abgagt_command_create.clas.abap +0 -95
  35. package/abap/zcl_abgagt_command_create.clas.xml +0 -15
  36. package/abap/zcl_abgagt_command_import.clas.abap +0 -138
  37. package/abap/zcl_abgagt_command_import.clas.xml +0 -15
  38. package/abap/zcl_abgagt_command_inspect.clas.abap +0 -456
  39. package/abap/zcl_abgagt_command_inspect.clas.testclasses.abap +0 -121
  40. package/abap/zcl_abgagt_command_inspect.clas.xml +0 -16
  41. package/abap/zcl_abgagt_command_preview.clas.abap +0 -386
  42. package/abap/zcl_abgagt_command_preview.clas.xml +0 -15
  43. package/abap/zcl_abgagt_command_pull.clas.abap +0 -80
  44. package/abap/zcl_abgagt_command_pull.clas.testclasses.abap +0 -87
  45. package/abap/zcl_abgagt_command_pull.clas.xml +0 -16
  46. package/abap/zcl_abgagt_command_tree.clas.abap +0 -237
  47. package/abap/zcl_abgagt_command_tree.clas.xml +0 -15
  48. package/abap/zcl_abgagt_command_unit.clas.abap +0 -297
  49. package/abap/zcl_abgagt_command_unit.clas.xml +0 -15
  50. package/abap/zcl_abgagt_command_view.clas.abap +0 -240
  51. package/abap/zcl_abgagt_command_view.clas.xml +0 -15
  52. package/abap/zcl_abgagt_resource_create.clas.abap +0 -71
  53. package/abap/zcl_abgagt_resource_create.clas.xml +0 -15
  54. package/abap/zcl_abgagt_resource_health.clas.abap +0 -25
  55. package/abap/zcl_abgagt_resource_health.clas.xml +0 -15
  56. package/abap/zcl_abgagt_resource_import.clas.abap +0 -66
  57. package/abap/zcl_abgagt_resource_import.clas.xml +0 -15
  58. package/abap/zcl_abgagt_resource_inspect.clas.abap +0 -63
  59. package/abap/zcl_abgagt_resource_inspect.clas.xml +0 -15
  60. package/abap/zcl_abgagt_resource_preview.clas.abap +0 -67
  61. package/abap/zcl_abgagt_resource_preview.clas.xml +0 -15
  62. package/abap/zcl_abgagt_resource_pull.clas.abap +0 -71
  63. package/abap/zcl_abgagt_resource_pull.clas.xml +0 -15
  64. package/abap/zcl_abgagt_resource_tree.clas.abap +0 -70
  65. package/abap/zcl_abgagt_resource_tree.clas.xml +0 -15
  66. package/abap/zcl_abgagt_resource_unit.clas.abap +0 -64
  67. package/abap/zcl_abgagt_resource_unit.clas.xml +0 -15
  68. package/abap/zcl_abgagt_resource_view.clas.abap +0 -68
  69. package/abap/zcl_abgagt_resource_view.clas.xml +0 -15
  70. package/abap/zcl_abgagt_rest_handler.clas.abap +0 -32
  71. package/abap/zcl_abgagt_rest_handler.clas.xml +0 -15
  72. package/abap/zcl_abgagt_util.clas.abap +0 -93
  73. package/abap/zcl_abgagt_util.clas.testclasses.abap +0 -84
  74. package/abap/zcl_abgagt_util.clas.xml +0 -16
  75. package/abap/zcl_abgagt_viewer_clas.clas.abap +0 -58
  76. package/abap/zcl_abgagt_viewer_clas.clas.xml +0 -15
  77. package/abap/zcl_abgagt_viewer_ddls.clas.abap +0 -83
  78. package/abap/zcl_abgagt_viewer_ddls.clas.xml +0 -15
  79. package/abap/zcl_abgagt_viewer_dtel.clas.abap +0 -98
  80. package/abap/zcl_abgagt_viewer_dtel.clas.xml +0 -15
  81. package/abap/zcl_abgagt_viewer_factory.clas.abap +0 -41
  82. package/abap/zcl_abgagt_viewer_factory.clas.xml +0 -15
  83. package/abap/zcl_abgagt_viewer_intf.clas.abap +0 -58
  84. package/abap/zcl_abgagt_viewer_intf.clas.xml +0 -15
  85. package/abap/zcl_abgagt_viewer_stru.clas.abap +0 -59
  86. package/abap/zcl_abgagt_viewer_stru.clas.xml +0 -15
  87. package/abap/zcl_abgagt_viewer_tabl.clas.abap +0 -59
  88. package/abap/zcl_abgagt_viewer_tabl.clas.xml +0 -15
  89. package/abap/zcl_abgagt_viewer_ttyp.clas.abap +0 -93
  90. package/abap/zcl_abgagt_viewer_ttyp.clas.xml +0 -15
  91. package/abap/zif_abgagt_agent.intf.abap +0 -53
  92. package/abap/zif_abgagt_agent.intf.xml +0 -15
  93. package/abap/zif_abgagt_cmd_factory.intf.abap +0 -7
  94. package/abap/zif_abgagt_cmd_factory.intf.xml +0 -15
  95. package/abap/zif_abgagt_command.intf.abap +0 -26
  96. package/abap/zif_abgagt_command.intf.xml +0 -15
  97. package/abap/zif_abgagt_util.intf.abap +0 -28
  98. package/abap/zif_abgagt_util.intf.xml +0 -15
  99. package/abap/zif_abgagt_viewer.intf.abap +0 -12
  100. package/abap/zif_abgagt_viewer.intf.xml +0 -15
  101. package/docs/commands.md +0 -142
  102. package/docs/create-command.md +0 -129
  103. package/docs/health-command.md +0 -89
  104. package/docs/import-command.md +0 -195
  105. package/docs/init-command.md +0 -189
  106. package/docs/inspect-command.md +0 -169
  107. package/docs/list-command.md +0 -289
  108. package/docs/preview-command.md +0 -528
  109. package/docs/pull-command.md +0 -202
  110. package/docs/status-command.md +0 -68
  111. package/docs/tree-command.md +0 -303
  112. package/docs/unit-command.md +0 -167
  113. package/docs/view-command.md +0 -501
  114. package/img/claude.png +0 -0
  115. package/scripts/claude-integration.js +0 -351
  116. package/scripts/release.js +0 -298
  117. package/scripts/release.sh +0 -60
  118. package/scripts/test-integration.js +0 -139
  119. package/scripts/unrelease.js +0 -277
package/README.md CHANGED
@@ -154,6 +154,7 @@ npm run pull -- --url <git-url> --branch main
154
154
  | tree Command | [docs/tree-command.md](docs/tree-command.md) |
155
155
  | view Command | [docs/view-command.md](docs/view-command.md) |
156
156
  | preview Command | [docs/preview-command.md](docs/preview-command.md) |
157
+ | ref Command | [docs/ref-command.md](docs/ref-command.md) |
157
158
  | REST API Reference | [API.md](API.md) |
158
159
  | Error Handling | [ERROR_HANDLING.md](ERROR_HANDLING.md) |
159
160
  | ABAP Coding Guidelines | [abap/CLAUDE.md](abap/CLAUDE.md) |
@@ -0,0 +1,36 @@
1
+ # ABAP Coding Guidelines Index
2
+
3
+ This folder contains detailed ABAP coding guidelines that can be searched using the `ref` command.
4
+
5
+ ## Guidelines Available
6
+
7
+ | File | Topic |
8
+ |------|-------|
9
+ | `01_sql.md` | ABAP SQL Best Practices |
10
+ | `02_exceptions.md` | Exception Handling |
11
+ | `03_testing.md` | Unit Testing (including CDS) |
12
+ | `04_cds.md` | CDS Views |
13
+ | `05_classes.md` | ABAP Classes and Objects |
14
+ | `06_objects.md` | Object Naming Conventions |
15
+ | `07_json.md` | JSON Handling |
16
+ | `08_abapgit.md` | abapGit XML Metadata Templates |
17
+ | `09_unit_testable_code.md` | Unit Testable Code Guidelines (Dependency Injection) |
18
+
19
+ ## Usage
20
+
21
+ These guidelines are automatically searched by the `ref` command:
22
+
23
+ ```bash
24
+ # Search across all guidelines
25
+ abapgit-agent ref "CORRESPONDING"
26
+
27
+ # List all topics
28
+ abapgit-agent ref --list-topics
29
+ ```
30
+
31
+ ## Adding Custom Guidelines
32
+
33
+ To add your own guidelines:
34
+ 1. Create a new `.md` file in this folder
35
+ 2. Follow the naming convention: `XX_name.md`
36
+ 3. Export to reference folder: `abapgit-agent ref export`
@@ -0,0 +1,88 @@
1
+ # ABAP SQL Best Practices
2
+
3
+ **Searchable keywords**: SELECT, FROM, WHERE, ABAP SQL, Open SQL, host variable, @ prefix, range table, INTO, UP TO, OFFSET, GROUP BY, JOIN
4
+
5
+ When writing ABAP SQL (Open SQL) queries, follow these rules:
6
+
7
+ ## TOPICS IN THIS FILE
8
+ 1. Host Variables (@ prefix) - line 5
9
+ 2. Range Tables (IN clause) - line 17
10
+ 3. SELECT Clause Order - line 35
11
+ 4. Fixed Point Arithmetic - line 52
12
+ 5. Field Separation - line 62
13
+
14
+ ## 1. Host Variables - Use @ Prefix
15
+
16
+ Use `@` prefix for host variables in ABAP SQL:
17
+
18
+ ```abap
19
+ " Correct
20
+ SELECT * FROM tadir WHERE devclass = @lv_package.
21
+
22
+ " Wrong - no @ prefix
23
+ SELECT * FROM tadir WHERE devclass = lv_package.
24
+ ```
25
+
26
+ ## 2. Range Tables for IN Clauses
27
+
28
+ When filtering with `IN`, use a range table with `@` prefix:
29
+
30
+ ```abap
31
+ " Define range table
32
+ DATA lt_type_range TYPE RANGE OF tadir-object.
33
+ ls_type-sign = 'I'.
34
+ ls_type-option = 'EQ'.
35
+ ls_type-low = 'CLAS'.
36
+ APPEND ls_type TO lt_type_range.
37
+
38
+ " Use with @ prefix
39
+ SELECT object, obj_name FROM tadir
40
+ WHERE object IN @lt_type_range
41
+ INTO TABLE @lt_objects.
42
+ ```
43
+
44
+ ## 3. SELECT Statement Clause Order
45
+
46
+ The correct sequence is:
47
+ ```
48
+ SELECT → FROM → WHERE → ORDER BY → INTO → UP TO → OFFSET
49
+ ```
50
+
51
+ ```abap
52
+ SELECT object, obj_name FROM tadir
53
+ WHERE devclass = @lv_package
54
+ AND object IN @lt_type_range
55
+ ORDER BY object, obj_name
56
+ INTO TABLE @lt_objects
57
+ UP TO @lv_limit ROWS
58
+ OFFSET @lv_offset.
59
+ ```
60
+
61
+ ## 4. Fixed Point Arithmetic (FIXPT)
62
+
63
+ For numeric operations in ABAP SQL (especially with UP TO/OFFSET), enable FIXPT in the class XML:
64
+
65
+ ```xml
66
+ <VSEOCLASS>
67
+ <FIXPT>X</FIXPT>
68
+ </VSEOCLASS>
69
+ ```
70
+
71
+ ## 5. Field Separation
72
+
73
+ Always separate fields with commas in SELECT:
74
+
75
+ ```abap
76
+ " Correct
77
+ SELECT object, obj_name FROM tadir ...
78
+
79
+ " Wrong - missing comma
80
+ SELECT object obj_name FROM tadir ...
81
+ ```
82
+
83
+ ---
84
+
85
+ ## See Also
86
+ - **Constructor Expressions** (05_classes.md) - for VALUE #(), FILTER, FOR loops
87
+ - **Internal Tables** - for filtering and iteration patterns
88
+ - **abapGit** (08_abapgit.md) - for XML metadata templates
@@ -0,0 +1,176 @@
1
+ # Exception Handling - Classical vs Class-Based
2
+
3
+ **Searchable keywords**: exception, RAISING, TRY, CATCH, cx_static_check, cx_dynamic_check, EXCEPTIONS, sy-subrc, class-based exception, classical exception
4
+
5
+ ## TOPICS IN THIS FILE
6
+ 1. Quick Identification - line 5
7
+ 2. Classical Exceptions - line 12
8
+ 3. Class-Based Exceptions - line 25
9
+ 4. Method Signatures - line 50
10
+ 5. Best Practices - line 80
11
+ 6. Interface vs Class Methods - line 118
12
+
13
+ ABAP has two exception handling mechanisms. Using the wrong one causes silent failures.
14
+
15
+ ## Quick Identification
16
+
17
+ | Method Signature | Exception Type | Handling Pattern |
18
+ |-----------------|----------------|------------------|
19
+ | `EXCEPTIONS exc = 1` | Classical | `sy-subrc` check |
20
+ | `RAISING cx_...` | Class-based | `TRY-CATCH` |
21
+
22
+ ## Classical Exceptions (Old Style)
23
+
24
+ Methods declared with `EXCEPTIONS` in signature:
25
+
26
+ ```abap
27
+ " Method declaration
28
+ class-methods describe_by_name
29
+ importing p_name type any
30
+ returning value(p_descr_ref) type ref to cl_abap_typedescr
31
+ exceptions
32
+ type_not_found. " <- Classical!
33
+
34
+ " Calling with classical exception
35
+ cl_abap_structdescr=>describe_by_name(
36
+ EXPORTING
37
+ p_name = iv_tabname
38
+ RECEIVING
39
+ p_descr_ref = lo_descr
40
+ EXCEPTIONS
41
+ type_not_found = 1
42
+ OTHERS = 2 ).
43
+ IF sy-subrc <> 0.
44
+ " Handle error
45
+ ENDIF.
46
+ ```
47
+
48
+ **Common classical exception methods:**
49
+ - `cl_abap_structdescr=>describe_by_name` - `type_not_found`
50
+ - `cl_abap_tabledescr=>describe_by_name` - `type_not_found`
51
+ - Many RTTI (Run Time Type Information) methods
52
+
53
+ ## Class-Based Exceptions (Modern)
54
+
55
+ Methods declared with `RAISING`:
56
+
57
+ ```abap
58
+ " Method declaration
59
+ methods get_ref
60
+ importing p_name type string
61
+ returning value(p_ref) type ref to cl_ci_checkvariant
62
+ raising cx_ci_checkvariant. " <- Class-based!
63
+
64
+ " Calling with TRY-CATCH
65
+ TRY.
66
+ lo_variant = cl_ci_checkvariant=>get_ref( p_name = lv_variant ).
67
+ CATCH cx_ci_checkvariant INTO DATA(lx_error).
68
+ " Handle error
69
+ ENDTRY.
70
+ ```
71
+
72
+ ## The Mistake to Avoid
73
+
74
+ **WRONG**: Using TRY-CATCH for classical exceptions
75
+ ```abap
76
+ " This does NOT catch type_not_found!
77
+ TRY.
78
+ lo_descr = cl_abap_structdescr=>describe_by_name( iv_name ).
79
+ CATCH cx_root. " Never reached!
80
+ ENDTRY.
81
+ ```
82
+
83
+ **CORRECT**: Use proper pattern for each type
84
+ ```abap
85
+ " Classical - use sy-subrc
86
+ cl_abap_structdescr=>describe_by_name(
87
+ EXPORTING p_name = iv_name
88
+ RECEIVING p_descr_ref = lo_descr
89
+ EXCEPTIONS type_not_found = 1 ).
90
+ IF sy-subrc <> 0.
91
+ " Handle error
92
+ ENDIF.
93
+
94
+ " Class-based - use TRY-CATCH
95
+ TRY.
96
+ lo_obj = cl_ci_checkvariant=>get_ref( lv_name ).
97
+ CATCH cx_root INTO DATA(lx_error).
98
+ " Handle error
99
+ ENDTRY.
100
+ ```
101
+
102
+ ## How to Check Which to Use
103
+
104
+ Use the `view` command to check method signature:
105
+
106
+ ```bash
107
+ abapgit-agent view --objects CL_ABAP_STRUCTDESCR
108
+ ```
109
+
110
+ Look for:
111
+ - `exceptions TYPE_NOT_FOUND` → Classical (use `sy-subrc`)
112
+ - `raising CX_SY_RTTI` → Class-based (use `TRY-CATCH`)
113
+
114
+ Or search the cheat sheets:
115
+
116
+ ```bash
117
+ abapgit-agent ref --topic exceptions
118
+ ```
119
+
120
+ ## Interface vs Class Methods
121
+
122
+ ### Interface Methods
123
+
124
+ Cannot add RAISING clause in the implementing class. Options:
125
+
126
+ 1. Add RAISING to interface definition
127
+ 2. Use TRY-CATCH in the implementation
128
+
129
+ ```abap
130
+ " Interface definition - can add RAISING here
131
+ INTERFACE zif_example.
132
+ methods execute
133
+ importing is_param type data optional
134
+ returning value(rv_result) type string
135
+ raising cx_static_check.
136
+ ENDINTERFACE.
137
+
138
+ " Implementation - CANNOT add RAISING here
139
+ CLASS zcl_example DEFINITION.
140
+ INTERFACES zif_example.
141
+ ENDCLASS.
142
+
143
+ CLASS zcl_example IMPLEMENTATION.
144
+ METHOD zif_example~execute.
145
+ " Must handle cx_static_check here with TRY-CATCH
146
+ " or declare it in interface, not here
147
+ ENDMETHOD.
148
+ ENDCLASS.
149
+ ```
150
+
151
+ ### Class Methods
152
+
153
+ Can add RAISING clause to declare exceptions, allowing caller to handle in one place:
154
+
155
+ ```abap
156
+ " Class method with RAISING clause
157
+ METHODS process_data
158
+ importing iv_data type string
159
+ returning value(rv_result) type string
160
+ raising cx_static_check.
161
+
162
+ " Caller can handle in one place
163
+ TRY.
164
+ lv_result = lo_obj->process_data( iv_data = 'test' ).
165
+ CATCH cx_static_check.
166
+ " Handle exception
167
+ ENDTRY.
168
+ ```
169
+
170
+ ### When to Use Each
171
+
172
+ | Scenario | Recommendation |
173
+ |----------|----------------|
174
+ | Multiple callers need to handle exception | Add RAISING to method definition |
175
+ | Exception should be handled internally | Use TRY-CATCH in implementation |
176
+ | Interface method | Add RAISING to interface, or use TRY-CATCH in class |
@@ -0,0 +1,269 @@
1
+ # Unit Testing
2
+
3
+ **Searchable keywords**: unit test, AUnit, test class, cl_abap_unit_assert, FOR TESTING, setup, teardown, RISK LEVEL, DURATION, CDS test double, CL_CDS_TEST_ENVIRONMENT
4
+
5
+ ## TOPICS IN THIS FILE
6
+ 1. Local Test Classes - line 3
7
+ 2. File Structure - line 5
8
+ 3. Required Elements - line 16
9
+ 4. Naming Conventions - line 48
10
+ 5. CDS Test Doubles - line 94
11
+ 6. CDS with Aggregations - line 178
12
+
13
+ ## Unit Testing with Local Test Classes
14
+
15
+ ### File Structure
16
+
17
+ For ABAP local unit tests, use a **separate file** with `.testclasses.abap` extension:
18
+
19
+ ```
20
+ abap/
21
+ zcl_my_class.clas.abap <- Main class (no test code)
22
+ zcl_my_class.clas.testclasses.abap <- Local test class
23
+ zcl_my_class.clas.xml <- XML with WITH_UNIT_TESTS = X
24
+ ```
25
+
26
+ ### Required Elements
27
+
28
+ 1. **Test class file** (`zcl_my_class.clas.testclasses.abap`):
29
+ ```abap
30
+ *"* use this source file for your test class implementation
31
+ *"* local test class
32
+ CLASS ltcl_zcl_my_class DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
33
+ PRIVATE SECTION.
34
+ DATA mo_cut TYPE REF TO zcl_my_class.
35
+ METHODS setup.
36
+ METHODS test_method1 FOR TESTING.
37
+ METHODS test_method2 FOR TESTING.
38
+ ENDCLASS.
39
+
40
+ CLASS ltcl_zcl_my_class IMPLEMENTATION.
41
+ METHOD setup.
42
+ CREATE OBJECT mo_cut.
43
+ ENDMETHOD.
44
+ METHOD test_method1.
45
+ " Test code using cl_abap_unit_assert
46
+ ENDMETHOD.
47
+ ENDCLASS.
48
+ ```
49
+
50
+ 2. **XML metadata** (`zcl_my_class.clas.xml`):
51
+ ```xml
52
+ <VSEOCLASS>
53
+ ...
54
+ <WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>
55
+ </VSEOCLASS>
56
+ ```
57
+
58
+ ### Naming Conventions
59
+
60
+ - Test class name: `LTCL_ZCL_<CLASSNAME>` (e.g., `LTCL_ZCL_COMMAND_PULL`)
61
+ - Test methods: `TEST_<methodname> FOR TESTING` or simply `test_method FOR TESTING`
62
+ - Test file: `<classname>.clas.testclasses.abap`
63
+
64
+ ### CRITICAL: Method Name Length Limit
65
+
66
+ **Test method names MUST NOT exceed 30 characters!**
67
+
68
+ ```abap
69
+ " WRONG - 34 characters (syntax error)
70
+ METHODS test_execute_with_minimal_params FOR TESTING.
71
+
72
+ " CORRECT - 18 characters
73
+ METHODS test_exec_minimal FOR TESTING.
74
+ ```
75
+
76
+ Examples of compliant names:
77
+ - `test_get_name` (13 chars)
78
+ - `test_exec_minimal` (18 chars)
79
+ - `test_exec_files` (16 chars)
80
+ - `test_interface` (15 chars)
81
+
82
+ ### Common Assertions
83
+
84
+ ```abap
85
+ cl_abap_unit_assert=>assert_equals( act = lv_actual exp = lv_expected msg = 'Error message' ).
86
+ cl_abap_unit_assert=>assert_not_initial( act = lv_data msg = 'Should not be initial' ).
87
+ cl_abap_unit_assert=>assert_bound( act = lo_ref msg = 'Should be bound' ).
88
+ cl_abap_unit_assert=>assert_true( act = lv_bool msg = 'Should be true' ).
89
+ ```
90
+
91
+ ### What NOT To Do
92
+
93
+ - ❌ Don't add test methods directly in the main `.clas.abap` file
94
+ - ❌ Don't use `CLASS ... DEFINITION ...` without the special comment header
95
+ - ❌ Don't reference `<TESTCLASS>` in XML - abapGit auto-detects `.testclasses.abap`
96
+ - ❌ Don't use nested local classes inside the main class definition
97
+
98
+ ### Running Tests
99
+
100
+ In ABAP: SE24 → Test → Execute Unit Tests
101
+
102
+ Or via abapGit: Pull the files and run tests in the ABAP system.
103
+
104
+ ## Unit Testing CDS Views
105
+
106
+ When testing code that uses CDS view entities, you can use the **CDS Test Double Framework** (`CL_CDS_TEST_ENVIRONMENT`) to create test doubles for CDS views. This allows you to inject test data without affecting production data.
107
+
108
+ ### When to Use CDS Test Doubles
109
+
110
+ - Testing code that reads from CDS views
111
+ - Need controlled test data (not production data)
112
+ - Testing CDS view logic with specific scenarios
113
+
114
+ ### CDS Test Double Framework
115
+
116
+ Use `CL_CDS_TEST_ENVIRONMENT` for controlled test data:
117
+
118
+ ```abap
119
+ "-------------------------
120
+ " CLASS DEFINITION
121
+ "-------------------------
122
+ CLASS ltcl_cds_test DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT FINAL.
123
+
124
+ PRIVATE SECTION.
125
+ " IMPORTANT: Use interface type, not class type!
126
+ DATA mo_cds_env TYPE REF TO if_cds_test_environment.
127
+
128
+ " IMPORTANT: class_setup/teardown must be CLASS-METHODS (static)!
129
+ CLASS-DATA mo_cds_env_static TYPE REF TO if_cds_test_environment.
130
+
131
+ METHODS setup.
132
+ METHODS test_cds_with_doubles FOR TESTING.
133
+
134
+ CLASS-METHODS: class_setup,
135
+ class_teardown.
136
+
137
+ ENDCLASS.
138
+
139
+ "-------------------------
140
+ " CLASS IMPLEMENTATION
141
+ "-------------------------
142
+ CLASS ltcl_cds_test IMPLEMENTATION.
143
+
144
+ METHOD class_setup.
145
+ " Create CDS test environment - framework auto-creates doubles for dependencies
146
+ mo_cds_env_static = cl_cds_test_environment=>create(
147
+ i_for_entity = 'ZC_MY_CDS_VIEW' ).
148
+ ENDMETHOD.
149
+
150
+ METHOD class_teardown.
151
+ " Clean up test environment
152
+ mo_cds_env_static->destroy( ).
153
+ ENDMETHOD.
154
+
155
+ METHOD setup.
156
+ " IMPORTANT: Assign static env to instance and clear doubles
157
+ mo_cds_env = mo_cds_env_static.
158
+ mo_cds_env->clear_doubles( ).
159
+ ENDMETHOD.
160
+
161
+ METHOD test_cds_with_doubles.
162
+ " IMPORTANT: Must declare table type first, cannot inline in VALUE!
163
+ DATA lt_test_data TYPE TABLE OF zc_my_cds_view WITH EMPTY KEY.
164
+ lt_test_data = VALUE #(
165
+ ( field1 = 'A' field2 = 100 )
166
+ ( field1 = 'B' field2 = 200 ) ).
167
+
168
+ " Insert test data using named parameter
169
+ mo_cds_env->insert_test_data( i_data = lt_test_data ).
170
+
171
+ " Select from CDS view
172
+ SELECT * FROM zc_my_cds_view INTO TABLE @DATA(lt_result).
173
+
174
+ " Verify results
175
+ cl_abap_unit_assert=>assert_not_initial(
176
+ act = lt_result
177
+ msg = 'Result should not be empty' ).
178
+
179
+ cl_abap_unit_assert=>assert_equals(
180
+ act = lines( lt_result )
181
+ exp = 2
182
+ msg = 'Expected 2 rows' ).
183
+ ENDMETHOD.
184
+
185
+ ENDCLASS.
186
+ ```
187
+
188
+ ### Testing CDS Views with Aggregations (SUM, COUNT, GROUP BY)
189
+
190
+ For CDS views with aggregations, insert test data into the **base tables** (SFLIGHT, SCARR, SBOOK), not directly into the CDS view:
191
+
192
+ ```abap
193
+ METHOD test_aggregation.
194
+ " Insert data into base tables via CDS test doubles
195
+ DATA lt_scarr TYPE TABLE OF scarr WITH EMPTY KEY.
196
+ lt_scarr = VALUE #( ( carrid = 'LH' carrname = 'Lufthansa' currcode = 'EUR' ) ).
197
+ mo_cds_env->insert_test_data( i_data = lt_scarr ).
198
+
199
+ DATA lt_sflight TYPE TABLE OF sflight WITH EMPTY KEY.
200
+ lt_sflight = VALUE #( ( carrid = 'LH' connid = '0400' fldate = '20240115'
201
+ seatsmax = 200 seatsocc = 100 ) ).
202
+ mo_cds_env->insert_test_data( i_data = lt_sflight ).
203
+
204
+ DATA lt_sbook TYPE TABLE OF sbook WITH EMPTY KEY.
205
+ lt_sbook = VALUE #(
206
+ ( carrid = 'LH' connid = '0400' fldate = '20240115' bookid = '0001' forcuram = 1000 )
207
+ ( carrid = 'LH' connid = '0400' fldate = '20240115' bookid = '0002' forcuram = 2000 )
208
+ ( carrid = 'LH' connid = '0400' fldate = '20240115' bookid = '0003' forcuram = 3000 ) ).
209
+ mo_cds_env->insert_test_data( i_data = lt_sbook ).
210
+
211
+ " Select from CDS view - aggregations will use test double data
212
+ SELECT * FROM zc_flight_revenue INTO TABLE @DATA(lt_result).
213
+
214
+ " Verify aggregations
215
+ cl_abap_unit_assert=>assert_equals(
216
+ exp = 3
217
+ act = lt_result[ 1 ]-numberofbookings
218
+ msg = 'Should have 3 bookings' ).
219
+
220
+ cl_abap_unit_assert=>assert_equals(
221
+ exp = '6000.00'
222
+ act = lt_result[ 1 ]-totalrevenue
223
+ msg = 'Total revenue should be 6000.00' ).
224
+ ENDMETHOD.
225
+ ```
226
+
227
+ ### Key Classes for CDS Testing
228
+
229
+ | Item | Type/Usage |
230
+ |------|------------|
231
+ | `CL_CDS_TEST_ENVIRONMENT` | Class with `CREATE` method |
232
+ | `IF_CDS_TEST_ENVIRONMENT` | Interface (CREATE returns this type) |
233
+ | `CLASS-METHODS` | `class_setup` and `class_teardown` must be static methods |
234
+ | `CL_OSQL_TEST_ENVIRONMENT` | Test doubles for database tables (use for aggregations) |
235
+ | `CL_ABAP_UNIT_ASSERT` | Assertions |
236
+
237
+ ### Key Methods
238
+
239
+ | Method | Purpose |
240
+ |--------|---------|
241
+ | `CL_CDS_TEST_ENVIRONMENT=>create( i_for_entity = ... )` | Create test environment (returns `if_cds_test_environment`) |
242
+ | `insert_test_data( i_data = ... )` | Insert test data into test doubles |
243
+ | `clear_doubles` | Clear test data before each test method |
244
+ | `destroy` | Clean up after test class |
245
+
246
+ ### Important Usage Notes
247
+
248
+ 1. **Use interface type**: `DATA mo_cds_env TYPE REF TO if_cds_test_environment` - the CREATE method returns an interface reference
249
+ 2. **CLASS-METHODS required**: `class_setup` and `class_teardown` must be declared with `CLASS-METHODS` (not `METHODS`)
250
+ 3. **Table type declaration**: Must declare `DATA lt_tab TYPE TABLE OF <type> WITH EMPTY KEY` before using `VALUE #()`
251
+ 4. **Auto-created dependencies**: CDS framework auto-creates test doubles for base tables - do not specify `i_dependency_list`
252
+ 5. **Aggregations**: For CDS views with SUM/COUNT/GROUP BY, insert test data into base tables (SFLIGHT, SCARR, etc.)
253
+ 6. **Clear doubles**: Call `clear_doubles` in `setup` method before each test
254
+ 7. **Enable associations**: Set `test_associations = 'X'` only if testing CDS associations
255
+ 8. **Exception handling**: Declare test methods with `RAISING cx_static_check` for proper exception handling
256
+
257
+ ### Search Reference for More Details
258
+
259
+ ```bash
260
+ abapgit-agent ref "cl_cds_test_environment"
261
+ abapgit-agent ref --topic unit-tests
262
+ ```
263
+
264
+ ---
265
+
266
+ ## See Also
267
+ - **CDS Views** (04_cds.md) - for CDS view definitions and syntax
268
+ - **abapGit** (08_abapgit.md) - for WITH_UNIT_TESTS in XML metadata
269
+ - **ABAP SQL** (01_sql.md) - for SELECT statements in tests