ABAPadvanced

ABAP Unit Testing & Test-Driven Development

Writing automated unit tests for ABAP classes using the ABAP Unit framework, mocks, and test doubles.

ABAP Unit runs automated tests inside the SAP system. The framework is straightforward; the hard part is writing code that can be tested at all.

Unit testing an ABAP class without dependency injection is like trying to test a car engine while it's still bolted into the car; injecting a test double is like putting the engine on a test stand where you control every input and can measure every output precisely.

Key Concepts

1
A test class lives with the code it tests.
    CLASS ltcl_discount DEFINITION FOR TESTING
      DURATION SHORT RISK LEVEL HARMLESS.
      PRIVATE SECTION.
        METHODS calculates_bulk_rate FOR TESTING.
    ENDCLASS.
2
    CLASS ltcl_discount IMPLEMENTATION.
      METHOD calculates_bulk_rate.
        cl_abap_unit_assert=>assert_equals(
          act = lcl_discount=>rate( 150 )
          exp = '0.10'
          msg = 'orders over 100 get 10 percent' ).
      ENDMETHOD.
    ENDCLASS.
3
RISK LEVEL HARMLESS means the test changes no persistent data, so it is safe to run anywhere. DANGEROUS tests are blocked in production systems by configuration. DURATION tells the framework how long to allow.
RISK LEVEL HARMLESSDANGEROUSDURATION
4
Assertions come from cl_abap_unit_assert: assert_equals, assert_true, assert_initial, assert_bound, fail.
cl_abap_unit_assertassert_equalsassert_trueassert_initialassert_bound
5
Why most ABAP code cannot be tested. This method cannot:
6
    METHOD calculate_total.
      SELECT * FROM vbak INTO TABLE lt_orders WHERE kunnr = iv_kunnr.
      ...
    ENDMETHOD.
7
The test would need those exact rows in that system's database. It would be slow, it would break when somebody else changed the data, and it would behave differently in each system.
8
Dependency injection is the fix. The class asks for what it needs rather than fetching it:
9
    INTERFACE lif_order_reader.
      METHODS read IMPORTING iv_kunnr TYPE kunnr
                   RETURNING VALUE(rt) TYPE ty_t_orders.
    ENDINTERFACE.
10
    METHOD constructor.
      mo_reader = io_reader.      " real one in production
    ENDMETHOD.
11
The test passes a double that returns fixed rows. No database, fast, and the same result every run.
12
CL_ABAP_TESTDOUBLE writes the double for you. Rather than hand-coding a fake class:
CL_ABAP_TESTDOUBLE
13
    DATA(lo_double) = CAST lif_order_reader(
        cl_abap_testdouble=>create( 'LIF_ORDER_READER' ) ).
    cl_abap_testdouble=>configure_call( lo_double )->returning( lt_fixture ).
    lo_double->read( '0000001' ).
14
Test seams, for code you cannot restructure. Legacy code can wrap a database call in a TEST-SEAM / END-TEST-SEAM block, which a test replaces with its own implementation. It is a pragmatic compromise: better than no test, and not a substitute for an injectable design.
TEST-SEAMEND-TEST-SEAM
15
Where tests actually run. From the editor, and in the ABAP Test Cockpit (ATC), which can be configured to block a transport release when tests fail. In BTP and abapGit-based pipelines the same tests run in CI, which is what makes them a gate rather than a habit.
ATC
16
The practical argument for writing them. An ABAP report is usually tested by running the transaction and looking at the output. That takes minutes, covers one case, and is repeated by hand after every change. A test suite covers thirty cases in seconds, every time — and is the only way to change old code with any confidence that you have not broken it.
17
What the interviewer is probing.1. "How do you test code that reads the database?" Probing: the design question. Stalls: "You cannot." Moves up: separate the data access behind an interface and inject a test double, or use the test double framework for CDS and SQL.
18
2. "What is RISK LEVEL and DURATION for?" Probing: the detail. Stalls: "Nothing." *Moves up:* declaring whether a test changes data and how long it takes, so systems can restrict which tests run where.
19
3. "Why is TDD hard in a typical ABAP codebase?" Probing: honesty. Stalls: "It is not." Moves up: legacy reports mix selection, logic and output in one include with global data, so the first step is extraction, not test writing.
20
4. "What does ABAP Unit give you in a transport-based landscape?" Probing: the value. Stalls: "Nothing." Moves up: tests run in the system, so a transport into QA can be validated automatically rather than by manual retesting.