{"id":"e40c9d7b-df57-4280-8fa9-88a8bc88ec3c","shortId":"qwaLdp","kind":"skill","title":"abap-unit-testing","tagline":"Help with ABAP Unit testing including test class setup, assertions, test doubles, mocking frameworks, dependency injection, CDS test environments, SQL test environments, RAP BO test doubles, and test fixtures. Use when users ask about ABAP unit tests, test classes, test methods, ","description":"# ABAP Unit Testing\n\nGuide for writing effective ABAP Unit tests including test class setup, assertions, test doubles, mocking frameworks, and test environments for CDS, SQL, and RAP.\n\n## Workflow\n\n1. **Determine the testing goal**:\n   - Testing business logic in a class method\n   - Testing a CDS view entity\n   - Testing a RAP BO behavior implementation\n   - Testing database-dependent logic with SQL test doubles\n   - Setting up test doubles for external dependencies\n\n2. **Choose the right approach**:\n   - Direct unit test for pure logic (no dependencies)\n   - Constructor/setter injection for mockable dependencies\n   - CDS test environment for CDS view tests\n   - OSQL test environment for SQL-dependent code\n   - RAP BO test doubles for RAP behavior tests\n\n3. **Follow the AAA pattern**: Arrange → Act → Assert\n\n4. **Ensure test isolation**: Tests must not depend on persistent data or external systems\n\n## Test Class Fundamentals\n\n### Test Class Definition\n\n```abap\n\"! Test class for ZCL_MY_CLASS\nCLASS ltc_my_class DEFINITION FINAL FOR TESTING\n  DURATION SHORT\n  RISK LEVEL HARMLESS.\n\n  PRIVATE SECTION.\n    DATA cut TYPE REF TO zcl_my_class.  \"Class Under Test\n\n    CLASS-METHODS class_setup.    \"Once before all tests\n    CLASS-METHODS class_teardown. \"Once after all tests\n    METHODS setup.               \"Before each test\n    METHODS teardown.            \"After each test\n\n    METHODS test_calculate_total FOR TESTING.\n    METHODS test_validate_input  FOR TESTING.\n    METHODS test_empty_input     FOR TESTING RAISING cx_static_check.\nENDCLASS.\n\nCLASS ltc_my_class IMPLEMENTATION.\n\n  METHOD class_setup.\n    \" One-time setup for all tests in this class\n  ENDMETHOD.\n\n  METHOD class_teardown.\n    \" One-time cleanup\n  ENDMETHOD.\n\n  METHOD setup.\n    \" Create fresh instance before each test\n    cut = NEW #( ).\n  ENDMETHOD.\n\n  METHOD teardown.\n    \" Cleanup after each test\n  ENDMETHOD.\n\n  METHOD test_calculate_total.\n    \" Arrange\n    DATA(lv_quantity) = 5.\n    DATA(lv_price) = CONV decfloat34( '10.50' ).\n\n    \" Act\n    DATA(lv_result) = cut->calculate_total(\n      iv_quantity = lv_quantity\n      iv_price    = lv_price ).\n\n    \" Assert\n    cl_abap_unit_assert=>assert_equals(\n      act = lv_result\n      exp = CONV decfloat34( '52.50' )\n      msg = 'Total should be quantity * price' ).\n  ENDMETHOD.\n\n  METHOD test_validate_input.\n    cl_abap_unit_assert=>assert_true(\n      act = cut->validate_input( 'VALID_INPUT' )\n      msg = 'Valid input should return true' ).\n  ENDMETHOD.\n\n  METHOD test_empty_input.\n    TRY.\n        cut->validate_input( '' ).\n        cl_abap_unit_assert=>fail( msg = 'Should have raised exception' ).\n      CATCH zcx_validation_error INTO DATA(lx_error).\n        cl_abap_unit_assert=>assert_bound(\n          act = lx_error\n          msg = 'Exception should be raised for empty input' ).\n    ENDTRY.\n  ENDMETHOD.\n\nENDCLASS.\n```\n\n### Test Class Attributes\n\n| Attribute    | Options                               | Purpose                                                |\n| ------------ | ------------------------------------- | ------------------------------------------------------ |\n| `DURATION`   | `SHORT` / `MEDIUM` / `LONG`           | Expected execution time; `SHORT` < 1s (default for CI) |\n| `RISK LEVEL` | `HARMLESS` / `DANGEROUS` / `CRITICAL` | Impact on system data; `HARMLESS` = no DB changes      |\n\n### Test Method Additions\n\n| Addition                  | Purpose                                                            |\n| ------------------------- | ------------------------------------------------------------------ |\n| `FOR TESTING`             | Marks method as a test method                                      |\n| `RAISING cx_static_check` | Allows exceptions to propagate (test fails on unhandled exception) |\n\n## CL_ABAP_UNIT_ASSERT — Assertion Methods\n\n| Method                      | Purpose                     | Example                                                      |\n| --------------------------- | --------------------------- | ------------------------------------------------------------ |\n| `assert_equals`             | Value equality              | `assert_equals( act = result exp = 42 )`                     |\n| `assert_true`               | Boolean true                | `assert_true( act = lv_flag )`                               |\n| `assert_false`              | Boolean false               | `assert_false( act = lv_flag )`                              |\n| `assert_initial`            | Value is initial            | `assert_initial( act = lt_table )`                           |\n| `assert_not_initial`        | Value is not initial        | `assert_not_initial( act = lt_result )`                      |\n| `assert_bound`              | Reference is bound          | `assert_bound( act = lo_instance )`                          |\n| `assert_not_bound`          | Reference is not bound      | `assert_not_bound( act = lo_ref )`                           |\n| `assert_differs`            | Values are different        | `assert_differs( act = val1 exp = val2 )`                    |\n| `assert_char_cp`            | Character pattern match     | `assert_char_cp( act = lv_text exp = '*error*' )`            |\n| `assert_char_np`            | Character pattern no match  | `assert_char_np( act = lv_text exp = '*secret*' )`           |\n| `assert_number_between`     | Number in range             | `assert_number_between( number = val lower = 1 upper = 10 )` |\n| `assert_table_contains`     | Table contains line         | `assert_table_contains( line = wa table = lt_result )`       |\n| `assert_table_not_contains` | Table does not contain line | `assert_table_not_contains( line = wa table = lt_result )`   |\n| `assert_return_code`        | sy-subrc check              | `assert_return_code( act = sy-subrc exp = 0 )`               |\n| `fail`                      | Force test failure          | `fail( msg = 'Should not reach here' )`                      |\n\n### Common Assertion Patterns\n\n```abap\n\" Check table has expected number of entries\ncl_abap_unit_assert=>assert_equals(\n  act = lines( lt_result )\n  exp = 3\n  msg = 'Expected 3 result entries' ).\n\n\" Check exception message\nTRY.\n    cut->some_method( ).\n    cl_abap_unit_assert=>fail( msg = 'Expected exception' ).\n  CATCH zcx_my_exception INTO DATA(lx).\n    cl_abap_unit_assert=>assert_equals(\n      act = lx->get_text( )\n      exp = 'Expected error message' ).\nENDTRY.\n\n\" Check that table contains a specific key\ncl_abap_unit_assert=>assert_table_contains(\n  line  = VALUE zstructure( key_field = 'ABC' )\n  table = lt_result\n  msg   = 'Result should contain entry ABC' ).\n```\n\n## Dependency Injection & Test Doubles\n\n### Constructor Injection Pattern\n\n```abap\n\" Production interface\nINTERFACE zif_data_provider.\n  METHODS get_data\n    RETURNING VALUE(rt_data) TYPE ztab_data.\nENDINTERFACE.\n\n\" Production class with injectable dependency\nCLASS zcl_processor DEFINITION.\n  PUBLIC SECTION.\n    METHODS constructor\n      IMPORTING io_provider TYPE REF TO zif_data_provider OPTIONAL.\n    METHODS process\n      RETURNING VALUE(rv_result) TYPE string.\n  PRIVATE SECTION.\n    DATA mo_provider TYPE REF TO zif_data_provider.\nENDCLASS.\n\nCLASS zcl_processor IMPLEMENTATION.\n  METHOD constructor.\n    mo_provider = COND #(\n      WHEN io_provider IS BOUND THEN io_provider\n      ELSE NEW zcl_default_provider( ) ).\n  ENDMETHOD.\n\n  METHOD process.\n    DATA(lt_data) = mo_provider->get_data( ).\n    \" Process data...\n  ENDMETHOD.\nENDCLASS.\n```\n\n### Test Double (Manual Mock)\n\n```abap\n\" Test double implementing the interface\nCLASS ltd_data_provider DEFINITION FOR TESTING.\n  PUBLIC SECTION.\n    INTERFACES zif_data_provider.\n    DATA mt_test_data TYPE ztab_data.\nENDCLASS.\n\nCLASS ltd_data_provider IMPLEMENTATION.\n  METHOD zif_data_provider~get_data.\n    rt_data = mt_test_data.\n  ENDMETHOD.\nENDCLASS.\n\n\" Test class using the double\nCLASS ltc_processor DEFINITION FINAL FOR TESTING\n  DURATION SHORT RISK LEVEL HARMLESS.\n  PRIVATE SECTION.\n    DATA cut        TYPE REF TO zcl_processor.\n    DATA mo_provider TYPE REF TO ltd_data_provider.\n\n    METHODS setup.\n    METHODS test_process_with_data FOR TESTING.\nENDCLASS.\n\nCLASS ltc_processor IMPLEMENTATION.\n  METHOD setup.\n    mo_provider = NEW #( ).\n    cut = NEW #( io_provider = mo_provider ).\n  ENDMETHOD.\n\n  METHOD test_process_with_data.\n    \" Arrange — configure test double\n    mo_provider->mt_test_data = VALUE #(\n      ( key = '1' value = 'A' )\n      ( key = '2' value = 'B' ) ).\n\n    \" Act\n    DATA(lv_result) = cut->process( ).\n\n    \" Assert\n    cl_abap_unit_assert=>assert_not_initial( act = lv_result ).\n  ENDMETHOD.\nENDCLASS.\n```\n\n## CDS Test Environment\n\nUse `cl_cds_test_environment=>create( i_for_entity = 'ZI_ENTITY' )` to stub all data sources of a CDS view. Insert test data with `insert_test_data( )`, clear with `clear_doubles( )` in `setup`, and call `destroy( )` in `class_teardown`.\n\n## OSQL (Open SQL) Test Environment\n\nUse `cl_osql_test_environment=>create( i_dependency_list = ... )` to stub specific DB tables/views for testing SQL-dependent classes. Same lifecycle pattern as CDS test environment.\n\n## RAP BO Test Doubles\n\n- **Transactional buffer double** (`cl_botd_txbufdbl_bo_test_env`): For testing code that consumes a RAP BO via EML\n- **Mock EML API** (`cl_botd_mockemlapi_bo_test_env`): For testing RAP handler method implementations by configuring mock responses\n\n## Test Seams (Legacy Code)\n\nUse `TEST-SEAM` / `END-TEST-SEAM` in production code and `TEST-INJECTION` / `END-TEST-INJECTION` in tests. Prefer constructor injection for new code.\n\n> For full code examples of all the above, read [references/test-environment-examples.md](references/test-environment-examples.md).\n\n## Best Practices\n\n### Test Design\n\n- **One assertion concept per test** — each test should verify one behavior\n- **Descriptive test method names** — `test_reject_negative_quantity` not `test_1`\n- **Independent tests** — no test should depend on another test's outcome or execution order\n- **Fast tests** — use `DURATION SHORT` and avoid unnecessary setup\n\n### Test Isolation\n\n- Always use test doubles for external dependencies (DB, APIs, other BOs)\n- Use `setup` / `teardown` to ensure clean state\n- Use `class_setup` / `class_teardown` for expensive one-time setup (test environments)\n- Always call `clear_doubles( )` in `setup` for test environment classes\n- Always call `destroy( )` in `class_teardown`\n\n### Test Structure\n\n- Place test classes in local test include (test classes tab in ADT)\n- Prefix test doubles with `ltd_` (local test double)\n- Prefix test classes with `ltc_` (local test class)\n- Group related tests in the same test class\n\n### What to Test\n\n- Business logic and calculations\n- Validation rules and error cases\n- Edge cases (empty input, boundary values, null references)\n- CDS view calculations and aggregations\n- RAP handler logic (actions, validations, determinations)\n\n### What Not to Test\n\n- Framework-provided functionality (managed CRUD in RAP)\n- Simple getter/setter methods\n- ABAP runtime behavior\n\n## References\n\n- [SAP ABAP Cheat Sheets — ABAP Unit Tests](https://github.com/SAP-samples/abap-cheat-sheets/blob/main/14_ABAP_Unit_Tests.md)\n- [SAP Help — ABAP Unit](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenunit_test.htm)\n- [SAP Help — CDS Test Double Framework](https://help.sap.com/docs/abap-cloud/abap-development-tools-user-guide/cds-test-double-framework)\n- [SAP Help — RAP BO Test Doubles](https://help.sap.com/docs/abap-cloud/abap-rap/test)\n- [Clean ABAP — Testing](https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#testing)","tags":["abap","unit","testing","skills","likweitan","agent-skills","sap"],"capabilities":["skill","source-likweitan","skill-abap-unit-testing","topic-abap","topic-agent-skills","topic-sap"],"categories":["abap-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/likweitan/abap-skills/abap-unit-testing","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add likweitan/abap-skills","source_repo":"https://github.com/likweitan/abap-skills","install_from":"skills.sh"}},"qualityScore":"0.456","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 12 github stars · SKILL.md body (11,621 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-24T01:03:15.943Z","embedding":null,"createdAt":"2026-04-23T13:03:44.468Z","updatedAt":"2026-04-24T01:03:15.943Z","lastSeenAt":"2026-04-24T01:03:15.943Z","tsv":"'/doc/abapdocu_cp_index_htm/cloud/en-us/index.htm?file=abenunit_test.htm)':1393 '/docs/abap-cloud/abap-development-tools-user-guide/cds-test-double-framework)':1402 '/docs/abap-cloud/abap-rap/test)':1411 '/sap-samples/abap-cheat-sheets/blob/main/14_abap_unit_tests.md)':1386 '/sap/styleguides/blob/main/clean-abap/cleanabap.md#testing)':1417 '0':673 '1':74,623,1007,1216 '10':625 '10.50':325 '1s':445 '2':113,1011 '3':154,706,709 '4':162 '42':506 '5':319 '52.50':354 'aaa':157 'abap':2,7,39,46,53,182,343,367,394,412,489,687,696,720,735,757,785,886,1022,1373,1378,1381,1389,1413 'abap-unit-test':1 'abc':768,777 'act':160,326,348,372,417,503,513,522,532,545,555,568,578,591,606,668,701,740,1014,1028 'action':1355 'addit':464,465 'adt':1302 'aggreg':1351 'allow':479 'alway':1242,1273,1283 'anoth':1224 'api':1132,1250 'approach':117 'arrang':159,315,996 'ask':37 'assert':14,60,161,341,345,346,369,370,396,414,415,491,492,497,501,507,511,516,520,525,530,535,542,548,553,558,565,571,576,582,588,596,603,611,617,626,632,640,649,658,665,685,698,699,722,737,738,759,760,1020,1024,1025,1196 'attribut':433,434 'avoid':1237 'b':1013 'behavior':95,152,1205,1375 'best':1191 'bo':28,94,147,1108,1117,1127,1136,1406 'boolean':509,518 'bos':1252 'botd':1115,1134 'bound':416,549,552,554,560,564,567,859 'boundari':1343 'buffer':1112 'busi':80,1330 'calcul':245,313,331,1333,1349 'call':1070,1274,1284 'case':1338,1340 'catch':403,727 'cds':21,69,88,131,135,1033,1038,1054,1104,1347,1396 'chang':461 'char':583,589,597,604 'charact':585,599 'cheat':1379 'check':264,478,664,688,712,749 'choos':114 'ci':448 'cl':342,366,393,411,488,695,719,734,756,1021,1037,1081,1114,1133 'class':12,43,58,84,177,180,184,188,189,192,211,212,216,218,225,227,266,269,272,283,286,432,804,808,846,892,913,931,935,975,1073,1099,1261,1263,1282,1287,1293,1299,1313,1318,1326 'class-method':215,224 'clean':1258,1412 'cleanup':291,306 'clear':1063,1065,1275 'code':145,660,667,1122,1152,1163,1179,1182 'common':684 'concept':1197 'cond':854 'configur':997,1146 'constructor':782,815,851,1175 'constructor/setter':126 'consum':1124 'contain':628,630,634,643,647,652,752,762,775 'conv':323,352 'cp':584,590 'creat':295,1041,1085 'critic':453 'crud':1367 'cut':205,301,330,373,390,716,950,984,1018 'cx':262,476 'danger':452 'data':172,204,316,320,327,408,457,732,790,794,798,801,823,836,843,871,873,877,879,894,903,905,908,911,915,920,924,927,949,956,963,971,995,1004,1015,1050,1058,1062 'databas':99 'database-depend':98 'db':460,1092,1249 'decfloat34':324,353 'default':446,866 'definit':181,193,811,896,938 'depend':19,100,112,125,130,144,169,778,807,1087,1098,1222,1248 'descript':1206 'design':1194 'destroy':1071,1285 'determin':75,1357 'differ':572,575,577 'direct':118 'doubl':16,30,62,105,109,149,781,883,888,934,999,1066,1110,1113,1245,1276,1305,1310,1398,1408 'durat':197,437,942,1234 'edg':1339 'effect':52 'els':863 'eml':1129,1131 'empti':257,387,426,1341 'end':1158,1169 'end-test-inject':1168 'end-test-seam':1157 'endclass':265,430,845,881,912,929,974,1032 'endinterfac':802 'endmethod':284,292,303,310,361,384,429,868,880,928,990,1031 'endtri':428,748 'ensur':163,1257 'entiti':90,1044,1046 'entri':694,711,776 'env':1119,1138 'environ':23,26,67,133,140,1035,1040,1079,1084,1106,1272,1281 'equal':347,498,500,502,700,739 'error':406,410,419,595,746,1337 'exampl':496,1183 'except':402,421,480,487,713,726,730 'execut':442,1229 'exp':351,505,580,594,609,672,705,744 'expect':441,691,708,725,745 'expens':1266 'extern':111,174,1247 'fail':397,484,674,678,723 'failur':677 'fals':517,519,521 'fast':1231 'field':767 'final':194,939 'fixtur':33 'flag':515,524 'follow':155 'forc':675 'framework':18,64,1363,1399 'framework-provid':1362 'fresh':296 'full':1181 'function':1365 'fundament':178 'get':742,793,876 'getter/setter':1371 'github.com':1385,1416 'github.com/sap-samples/abap-cheat-sheets/blob/main/14_abap_unit_tests.md)':1384 'github.com/sap/styleguides/blob/main/clean-abap/cleanabap.md#testing)':1415 'goal':78 'group':1319 'guid':49 'handler':1142,1353 'harmless':201,451,458,946 'help':5,1388,1395,1404 'help.sap.com':1392,1401,1410 'help.sap.com/doc/abapdocu_cp_index_htm/cloud/en-us/index.htm?file=abenunit_test.htm)':1391 'help.sap.com/docs/abap-cloud/abap-development-tools-user-guide/cds-test-double-framework)':1400 'help.sap.com/docs/abap-cloud/abap-rap/test)':1409 'impact':454 'implement':96,270,849,889,917,978,1144 'import':816 'includ':10,56,1297 'independ':1217 'initi':526,529,531,537,541,544,1027 'inject':20,127,779,783,806,1167,1171,1176 'input':252,258,365,375,377,380,388,392,427,1342 'insert':1056,1060 'instanc':297,557 'interfac':787,788,891,901 'io':817,856,861,986 'isol':165,1241 'iv':333,337 'key':755,766,1006,1010 'legaci':1151 'level':200,450,945 'lifecycl':1101 'line':631,635,648,653,702,763 'list':1088 'lo':556,569 'local':1295,1308,1316 'logic':81,101,123,1331,1354 'long':440 'lower':622 'lt':533,546,638,656,703,770,872 'ltc':190,267,936,976,1315 'ltd':893,914,962,1307 'lv':317,321,328,335,339,349,514,523,592,607,1016,1029 'lx':409,418,733,741 'manag':1366 'manual':884 'mark':469 'match':587,602 'medium':439 'messag':714,747 'method':45,85,217,226,233,238,243,249,255,271,285,293,304,311,362,385,463,470,474,493,494,718,792,814,826,850,869,918,965,967,979,991,1143,1208,1372 'mo':837,852,874,957,981,988,1000 'mock':17,63,885,1130,1147 'mockabl':129 'mockemlapi':1135 'msg':355,378,398,420,679,707,724,772 'mt':906,925,1002 'must':167 'name':1209 'negat':1212 'new':302,864,983,985,1178 'np':598,605 'null':1345 'number':612,614,618,620,692 'one':275,289,1195,1204,1268 'one-tim':274,288,1267 'open':1076 'option':435,825 'order':1230 'osql':138,1075,1082 'outcom':1227 'pattern':158,586,600,686,784,1102 'per':1198 'persist':171 'place':1291 'practic':1192 'prefer':1174 'prefix':1303,1311 'price':322,338,340,360 'privat':202,834,947 'process':827,870,878,969,993,1019 'processor':810,848,937,955,977 'product':786,803,1162 'propag':482 'provid':791,818,824,838,844,853,857,862,867,875,895,904,916,921,958,964,982,987,989,1001,1364 'public':812,899 'pure':122 'purpos':436,466,495 'quantiti':318,334,336,359,1213 'rais':261,401,424,475 'rang':616 'rap':27,72,93,146,151,1107,1126,1141,1352,1369,1405 'reach':682 'read':1188 'ref':207,570,820,840,952,960 'refer':550,561,1346,1376 'references/test-environment-examples.md':1189,1190 'reject':1211 'relat':1320 'respons':1148 'result':329,350,504,547,639,657,704,710,771,773,831,1017,1030 'return':382,659,666,795,828 'right':116 'risk':199,449,944 'rt':797,923 'rule':1335 'runtim':1374 'rv':830 'sap':1377,1387,1394,1403 'seam':1150,1156,1160 'secret':610 'section':203,813,835,900,948 'set':106 'setup':13,59,219,234,273,277,294,966,980,1068,1239,1254,1262,1270,1278 'sheet':1380 'short':198,438,444,943,1235 'simpl':1370 'skill' 'skill-abap-unit-testing' 'sourc':1051 'source-likweitan' 'specif':754,1091 'sql':24,70,103,143,1077,1097 'sql-depend':142,1096 'state':1259 'static':263,477 'string':833 'structur':1290 'stub':1048,1090 'subrc':663,671 'sy':662,670 'sy-subrc':661,669 'system':175,456 'tab':1300 'tabl':534,627,629,633,637,641,644,650,655,689,751,761,769 'tables/views':1093 'teardown':228,239,287,305,1074,1255,1264,1288 'test':4,9,11,15,22,25,29,32,41,42,44,48,55,57,61,66,77,79,86,91,97,104,108,120,132,137,139,148,153,164,166,176,179,183,196,214,223,232,237,242,244,248,250,254,256,260,280,300,309,312,363,386,431,462,468,473,483,676,780,882,887,898,907,926,930,941,968,973,992,998,1003,1034,1039,1057,1061,1078,1083,1095,1105,1109,1118,1121,1137,1140,1149,1155,1159,1166,1170,1173,1193,1199,1201,1207,1210,1215,1218,1220,1225,1232,1240,1244,1271,1280,1289,1292,1296,1298,1304,1309,1312,1317,1321,1325,1329,1361,1383,1397,1407,1414 'test-inject':1165 'test-seam':1154 'text':593,608,743 'time':276,290,443,1269 'topic-abap' 'topic-agent-skills' 'topic-sap' 'total':246,314,332,356 'transact':1111 'tri':389,715 'true':371,383,508,510,512 'txbufdbl':1116 'type':206,799,819,832,839,909,951,959 'unhandl':486 'unit':3,8,40,47,54,119,344,368,395,413,490,697,721,736,758,1023,1382,1390 'unnecessari':1238 'upper':624 'use':34,932,1036,1080,1153,1233,1243,1253,1260 'user':36 'val':621 'val1':579 'val2':581 'valid':251,364,374,376,379,391,405,1334,1356 'valu':499,527,538,573,764,796,829,1005,1008,1012,1344 'verifi':1203 'via':1128 'view':89,136,1055,1348 'wa':636,654 'workflow':73 'write':51 'zcl':186,209,809,847,865,954 'zcx':404,728 'zi':1045 'zif':789,822,842,902,919 'zstructur':765 'ztab':800,910 '~get_data':922","prices":[{"id":"cf581328-617f-4b42-9f96-62a1fb8017f9","listingId":"e40c9d7b-df57-4280-8fa9-88a8bc88ec3c","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"likweitan","category":"abap-skills","install_from":"skills.sh"},"createdAt":"2026-04-23T13:03:44.468Z"}],"sources":[{"listingId":"e40c9d7b-df57-4280-8fa9-88a8bc88ec3c","source":"github","sourceId":"likweitan/abap-skills/abap-unit-testing","sourceUrl":"https://github.com/likweitan/abap-skills/tree/main/skills/abap-unit-testing","isPrimary":false,"firstSeenAt":"2026-04-23T13:03:44.468Z","lastSeenAt":"2026-04-24T01:03:15.943Z"}],"details":{"listingId":"e40c9d7b-df57-4280-8fa9-88a8bc88ec3c","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"likweitan","slug":"abap-unit-testing","github":{"repo":"likweitan/abap-skills","stars":12,"topics":["abap","agent-skills","sap"],"license":"mit","html_url":"https://github.com/likweitan/abap-skills","pushed_at":"2026-04-17T13:44:41Z","description":"Advance Agent Skills for ABAP Developers","skill_md_sha":"2363ac435b5f8b968588cec900b357013b50b969","skill_md_path":"skills/abap-unit-testing/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/likweitan/abap-skills/tree/main/skills/abap-unit-testing"},"layout":"multi","source":"github","category":"abap-skills","frontmatter":{"name":"abap-unit-testing","description":"Help with ABAP Unit testing including test class setup, assertions, test doubles, mocking frameworks, dependency injection, CDS test environments, SQL test environments, RAP BO test doubles, and test fixtures. Use when users ask about ABAP unit tests, test classes, test methods, CL_ABAP_UNIT_ASSERT, test doubles, mocking, CDS test environment, SQL test environment, RAP testing, ABAP test injection, test seams, behavior-driven testing, TDD in ABAP, test isolation, or writing automated tests for ABAP code. Triggers include \"write a unit test\", \"create test class\", \"mock a dependency\", \"test a CDS view\", \"test a RAP BO\", \"test double\", \"assertion\", \"test fixture\", \"test isolation\", or \"ABAP unit\"."},"skills_sh_url":"https://skills.sh/likweitan/abap-skills/abap-unit-testing"},"updatedAt":"2026-04-24T01:03:15.943Z"}}