AWS Builder Center

Your pure ABAP logic has zero tests — let an agent write them before you refactor

How SAP teams backfill ABAP Unit tests for untested business logic, lift coverage, and refactor safely using Anthropic Claude Opus 5 on Amazon Bedrock — grounded in a real 0-test calculator class.

Series: AI Assisted SAP ABAP workflows using Kiro Agents (1 article)

  1. 1
    Your pure ABAP logic has zero tests — let an agent write them before you refactor This article
🧪 There is a class in your system that computes money. It prices baggage, multiplies a fare by
travel class, and applies a group discount that increases at 5, 10, and 20 passengers. The class
contains pure logic: no database access, no UI, and the same output for the same input. It also has
zero ABAP Unit tests.
Everyone is a little afraid of it. Nobody wants to change the discount tiers, introduce an
off-by-one error, and then explain to Finance why a group of 20 received the 10% rate. The team
leaves the class alone because it feels too risky to refactor and too important to ignore. Missing
tests keep useful changes from moving forward. An agent can handle much of the repetitive work
needed to build that safety net.
This post covers AI-assisted test-driven development for ABAP. Foundation models on
Amazon Bedrock, used through Kiro CLI, read untested logic, generate an ABAP Unit test
class with boundaries and edge cases, run the tests, and provide the green result you need before
you change the implementation. A hands-on workshop  at the end lets you run the same process yourself.

The problem: untested logic you can't safely change

Meet Ravi, an ABAP developer on a team running SAP on AWS. He has been asked to add a fourth
discount tier to ZCL_SFLIGHT_CALCULATOR. He opens the class and finds three clear methods but no test class. The logic looks simple, which is exactly the problem: simple does not mean proven.
  • Refactoring is a leap of faith. Without a safety net, developers check every edit by reading
    the code and hoping they caught everything. People often miss the riskiest cases, especially tier
    boundaries, when they write tests by hand.
  • Writing tests is repetitive, so teams put it off. A complete test set must include the
    5/10/20 boundaries, the values just below them (4/9/19), zero and negative inputs, and every
    fare-class branch. That work is mechanical and easy to delay when a deadline is close.
  • Coverage is unknown. Nobody can say how much of the class the tests exercise, so nobody can
    confidently say that a change is safe.
A test-first approach addresses these problems. In practice, the time required to write the tests
often keeps teams from using it. The agent reduces that setup work while ABAP Unit remains the
final check.

The capability: generate, run, and green the tests, then refactor

The AWS AI capability here is agentic test authoring and coverage improvement. The model reads
the method under test, identifies branches and boundaries, and produces a syntactically valid
ABAP Unit test class that uses cl_abap_unit_assert. The tooling then runs the class through ADT's REST APIs and reports pass/fail results and coverage.
Four flows cover the lifecycle:
  1. Backfill: move from no tests to a working test class for existing untested logic.
  2. Coverage analysis: run ABAP Unit with coverage, find branches that are not exercised,
    generate tests for them, and report the coverage percentage increase.
  3. Refactor under tests: use a green suite as the behavioral contract while you restructure
    the code. The suite fails as soon as behavior changes.
  4. Test first for new code: describe the new behavior, let the agent write the failing test,
    and then implement the behavior until the test passes.
This process is safe because the agent proposes tests, but SAP's ABAP Unit runner makes the
final decision. If a generated test expects the wrong number, it fails on the real system and
must be corrected. The model cannot silently turn an incorrect result into a passing test.

The worked example: 0 → a full suite on a real class

Everything below uses a class on a live S/4HANA development system (SID S4H, client 100, package ZSFLIGHT). ZCL_SFLIGHT_CALCULATOR has 0 ABAP Unit tests even though it contains three pure methods:
  • calc_baggage_fee = (weight − free_limit) × rate
  • calc_class_multiplier: CASE maps F → 3.50, C → 2.00, and Y → 1.00
  • calc_group_discount: IF count ≥ 20 → 0.20, ≥ 10 → 0.15, ≥ 5 → 0.10, else 0
Ravi points the agent at the class and asks it to backfill the tests. The agent checks the boundary
conditions people often miss and generates a test class. Here is a faithful excerpt of the source:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
CLASS ltc_calculator DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO zcl_sflight_calculator. " code under test
METHODS setup.
METHODS baggage_fee_excess FOR TESTING.
METHODS baggage_fee_zero_weight FOR TESTING.
METHODS baggage_fee_at_limit FOR TESTING.
METHODS class_multiplier_all FOR TESTING.
METHODS group_discount_tiers FOR TESTING.
ENDCLASS.

CLASS ltc_calculator IMPLEMENTATION.
METHOD setup.
mo_cut = NEW #( ).
ENDMETHOD.

METHOD baggage_fee_excess.
" (28 - 20) * 4.50 = 36.00
cl_abap_unit_assert=>assert_equals(
exp = CONV decfloat34( '36.00' )
act = mo_cut->calc_baggage_fee(
iv_weight = 28 iv_free_limit = 20 iv_rate = '4.50' )
msg = '8 excess kg at 4.50/kg' ).
ENDMETHOD.

METHOD group_discount_tiers.
" boundary matrix around every tier edge
TYPES: BEGIN OF ty_case, cnt TYPE i, exp TYPE decfloat34, END OF ty_case.
DATA(lt_cases) = VALUE STANDARD TABLE OF ty_case(
( cnt = 4 exp = '0.00' ) ( cnt = 5 exp = '0.10' )
( cnt = 9 exp = '0.10' ) ( cnt = 10 exp = '0.15' )
( cnt = 19 exp = '0.15' ) ( cnt = 20 exp = '0.20' ) ).
LOOP AT lt_cases INTO DATA(ls).
cl_abap_unit_assert=>assert_equals(
exp = ls-exp
act = mo_cut->calc_group_discount( ls-cnt )
msg = |discount at count { ls-cnt }| ).
ENDLOOP.
ENDMETHOD.
ENDCLASS.
Notice the values that a developer in a hurry might miss. The agent tests the count just below
each tier (4, 9, 19) and the count at each tier (5, 10, 20). Those six assertions define the
exact >= boundaries. The suite also checks zero weight and a weight equal to the free limit.
Red → green. The first run is not all green, and that result matters. The agent initially expected calc_baggage_fee to return 0.00 for zero weight. The method actually returns a
negative fee when the weight is below the free limit because it has no floor:
(0 − 20) × 4.50 = −90.00. ABAP Unit reports the failed assertion:
1
2
Method BAGGAGE_FEE_ZERO_WEIGHT ... [FAILED]
Expected [0.00] Actual [90.00-]
The failed test shows a problem in the current logic: the class allows negative baggage fees.
The agent can update the test to record the current behavior, but it also flags the result for
Ravi. He must decide whether the behavior is intended or whether the calculation needs a floor at
zero. After he adds the floor and runs the suite again, every test passes. He can now add the
fourth discount tier with tests checking the existing behavior.
You just saw 0 tests become a boundary-complete suite that exposed a problem in the current
logic. The workshop below lets you run the same backfill → red → green process against a sandbox.

Performance at scale

Test generation can run across classes in parallel. The table shows the results from the dev
system and clearly marks model-dependent estimates as illustrative:
MetricValueSource
Tests generated for ZCL_SFLIGHT_CALCULATOR1 test class, ~12 assertions across 5 methods (real class, 3 methods)observed example
Coverage lift on the class~0% → high-90s% procedure/branch coverage after backfillillustrative
Wall-clock per small class (generate + run + reconcile)a few minutes, dominated by model latencyillustrative
Concurrencyclasses run in parallel, with one agent per classdesign
Boundary/edge cases per numeric methodthe generated suite includes tier edges plus zero/negative valuesobserved example
For planning, focus on tests per class and the coverage percentage increase. You can run the
agent overnight on a package of untested utility classes. The next morning, the team has tests and
a coverage report it can use in code review.

Build it in your landscape

Kiro CLI and the supporting tooling run on a small automation host. That host can be a laptop
for interactive work, or an EC2 instance or CI runner for batch work. The host invokes the model
through Amazon Bedrock. Every SAP request uses HTTPS to the ADT REST endpoints on a
development or sandbox system, never production.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
flowchart TB
subgraph AWS["Customer AWS account / VPC"]
direction TB
subgraph CONTROL["Secure automation"]
direction LR
SM["AWS Secrets Manager"]
HOST["Automation host<br/>Kiro CLI + abapctl"]
BR["Amazon Bedrock<br/>Claude Opus 5"]
end
SM -->|Credentials| HOST
HOST -->|Generate tests| BR
end

subgraph SAP["S/4HANA DEV"]
direction TB
subgraph ARTIFACTS["ABAP artifacts via ADT"]
direction LR
ADT["ADT REST API"]
SRC["ABAP source"]
SAVE{"Transport-controlled<br/>save"}
TEST["Test include"]
end
UNIT["ABAP Unit"]
ADT -->|Read| SRC
SAVE -->|Via ADT| TEST
SRC -->|Code under test| UNIT
TEST -->|Tests| UNIT
end

subgraph RESULTS["Validated output"]
direction TB
COV["Coverage report<br/>red to green"]
end

BR -->|Generated tests| SAVE
HOST -->|Connect| ADT
UNIT -->|Results| COV

classDef aws fill:#FFF3E0,stroke:#FF9900,stroke-width:2px,color:#1F2937;
classDef sap fill:#EAF3F8,stroke:#0A6ED1,stroke-width:2px,color:#1F2937;
classDef process fill:#F3F4F6,stroke:#6B7280,stroke-width:2px,color:#1F2937;
classDef gate fill:#ECFDF3,stroke:#1F8A4C,stroke-width:2px,color:#1F2937;
classDef output fill:#F3E8FF,stroke:#7E22CE,stroke-width:2px,color:#1F2937;

class SM,HOST,BR aws;
class ADT,SRC,TEST sap;
class UNIT process;
class SAVE gate;
class COV output;
  • AWS-native (self-managed SAP on AWS). The automation host runs in your VPC and connects
    directly to the DEV system's ADT endpoint. It retrieves the SAP developer password from
    AWS Secrets Manager at runtime and reaches Bedrock in the same Region through a
    VPC endpoint (PrivateLink).
  • SAP RISE on AWS. The DEV system runs in the SAP-managed RISE VPC. Your automation host runs in your account and reaches ADT through the RISE-provided connectivity path. It does not
    need direct database or operating system access because ADT REST provides everything required. Bedrock inference remains in your account.
What differs: With RISE, ABAP source moves from the SAP-managed environment to your account so the model can read it. Your team must document this data transfer, including what leaves, where it is processed, and which Region is used. Amazon Bedrock does not use prompts or completions to train the base models, and the data remains in your Region. This TDD flow sends source code and test results, not business data.

Which model, and what it costs

The model. Test generation uses Anthropic Claude Opus 5 on Amazon Bedrock. A strong
reasoning model is useful when it must identify all six values around the 5, 10, and 20 passenger
boundaries instead of choosing a few sample inputs. It can produce more complete suites with fewer compile errors than a smaller model.
Model on BedrockRelative cost/tokenImpact on this task
Claude Opus 5 (standard here)$$$Most complete edge-case coverage and the fewest broken tests to fix
Claude Sonnet-class$$Good for straightforward assertions; may miss some boundaries and costs less
Amazon Nova (lightweight)$Lowest cost and fastest; usually needs more compile fixes and may produce less coverage
ABAP Unit runs every generated test, regardless of the model. A smaller model cannot make an
incorrect result safe. It may produce tests that require more corrections or leave more branches
untested. Choose a model based on the coverage you need, the review effort you can accept, and the cost.
Cost of usage: tokens per class. Illustrative; confirm current rates on the
Amazon Bedrock pricing page . A small class such as the calculator, together with its prompt, uses roughly ~3-8k input tokens. The generated test class uses about ~1-3k output tokens. That works out to approximately cents to low tens of cents per class. Backfilling a package of untested
utility classes usually costs a few dollars in model inference, far less than the developer
time required to write every boundary test by hand.

SAP authorizations you'll need

This flow is mostly read-only. It can provide useful results before you grant any authorization to
save generated code. Confirm the exact authorization objects and values for your SAP
release with your security team.
ActionSAP authorization (typical)Tier
Reach the ADT REST endpointactive /sap/bc/adt ICF services + developer accessread
Read source and metadataS_DEVELOP (ACTVT 03 display)read
Run ABAP Unit with coverageABAP Unit execution authorizationread-ish (executes test code, no app write)
Save the generated test include + activateS_DEVELOP (ACTVT 01/02), S_TRANSPRTmutating
Start with a read/run user. Generate and execute tests in memory to demonstrate coverage
without writing to SAP. Add the mutating authorization only when you are ready to save the test
class under a transport. Use a DEV or sandbox user and limit it to the target package.

Alternatives, and when to choose them

  • Hand-written ABAP Unit tests. These give developers full control. Choose them when the
    intended behavior is subtle enough that a person must define it. The agent's failed test can
    still help reveal where that decision is needed.
  • SAP's native ABAP test tooling and ADT test-generation features. These tools are built into
    SAP. Choose the Kiro + Bedrock approach when you need a scriptable process in your own AWS
    account, a choice of models, and CI integration.
  • Coverage-only gating without generation. This measures the gap but does not add the missing
    tests. Use it with the agent so that a coverage drop can trigger test generation.
Generated tests can record a bug as expected behavior. Treat the first failed run as a review
checkpoint, as Ravi did, and have a developer review every assertion that affects money.

Try it yourself

You have seen a class with no tests become a boundary-complete suite that exposed a problem in
its current negative-fee logic. You have also seen how that suite supports a safe refactor. Now
run the complete process:
  • You'll build: a backfill → run → red-to-green process for ZCL_SFLIGHT_CALCULATOR, followed by a refactor protected by tests.
  • You'll leave with: a repeatable way to generate tests for an untested class and produce a
    coverage number that supports code review.
  • What you need: an AWS account with Amazon Bedrock access and a DEV or sandbox SAP connection. The workshop covers the setup. RISE customer? Use the same process over your approved RISE connectivity path.

Wrap-up

Untested pure logic often remains unchanged because writing the first useful test suite takes time.
An agent can generate the repetitive boundary and edge-case tests, while SAP's ABAP Unit runner
checks every result. This makes a test-first approach practical without weakening the review
process. The resulting green suite gives developers a safety net for each refactor.

Series: AI Assisted SAP ABAP workflows using Kiro Agents (1 article)

  1. 1
    Your pure ABAP logic has zero tests — let an agent write them before you refactor This article
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article