ABAP New Syntax Lecture 12: Complete Mini Project, ABAP Unit Tests and Interview Revision

ABAP New Syntax • Lecture 12

Complete Mini Project, ABAP Unit Tests & Interview Revision

Build a production-style sales analytics service using modern ABAP, verify it with automated tests, and revise the most important interview concepts.

Clean ArchitectureOpen SQLABAP UnitATC Ready
Learning outcome: By the end of this lecture, you can design a small business service, use constructor expressions and inline declarations safely, isolate database access, write ABAP Unit tests and explain the design in an interview.

Project scenario

A business user needs a report that summarizes sales orders by customer. Only orders from a selected date onward are considered. The output must show order count, total net value and a status such as High Value or Standard. We will keep database access separate from calculation logic so that tests run without production data.

1. Read
Fetch required fields only
2. Map
Convert DB rows to model
3. Aggregate
Use modern expressions
4. Test
Arrange, Act, Assert
5. Check
Run ATC and review

Step 1: Define clean types

Keep the public model small and explicit. Replace the demo fields with released CDS entities and domain types available in your system.

TYPES: BEGIN OF ty_order,
         customer_id TYPE kunnr,
         sales_order TYPE vbeln_va,
         net_value   TYPE netwr,
         currency    TYPE waers,
       END OF ty_order,
       tt_order TYPE STANDARD TABLE OF ty_order WITH EMPTY KEY.

TYPES: BEGIN OF ty_summary,
         customer_id TYPE kunnr,
         order_count TYPE i,
         total_value TYPE decfloat34,
         status      TYPE string,
       END OF ty_summary,
       tt_summary TYPE SORTED TABLE OF ty_summary
                  WITH UNIQUE KEY customer_id.

Step 2: Read only what you need

Modern Open SQL supports inline declarations and host variables marked with @. Avoid SELECT *; choosing only required columns reduces data transfer and makes the intent clear.

SELECT customer_id,
       sales_order,
       total_net_amount AS net_value,
       transaction_currency AS currency
  FROM i_salesorder
  WHERE creation_date >= @iv_date_from
  INTO TABLE @DATA(lt_orders).

IF lt_orders IS INITIAL.
  RETURN.
ENDIF.
Compatibility note: The CDS entity and field names vary by SAP release. Confirm released APIs in your system before copying the example.

Step 3: Aggregate with GROUP BY and REDUCE

The grouping expression avoids nested loops and keeps the calculation close to the business rule. REDUCE calculates totals without a temporary accumulator variable outside the expression.

LOOP AT it_orders INTO DATA(ls_order)
     GROUP BY ( customer_id = ls_order-customer_id )
     ASSIGNING FIELD-SYMBOL(<customer_group>).

  DATA(lv_total) = REDUCE decfloat34(
    INIT total = CONV decfloat34( 0 )
    FOR order IN GROUP <customer_group>
    NEXT total = total + order-net_value ).

  INSERT VALUE #(
    customer_id = <customer_group>-customer_id
    order_count = lines( VALUE tt_order(
                    FOR row IN GROUP <customer_group> ( row ) ) )
    total_value = lv_total
    status      = COND string(
                    WHEN lv_total >= 100000 THEN 'High Value'
                    ELSE 'Standard' ) )
    INTO TABLE rt_summary.
ENDLOOP.

Step 4: Put logic behind a testable class

CLASS zcl_sales_summary DEFINITION
  PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    METHODS summarize
      IMPORTING it_orders TYPE tt_order
      RETURNING VALUE(rt_summary) TYPE tt_summary.
ENDCLASS.

CLASS zcl_sales_summary IMPLEMENTATION.
  METHOD summarize.
    "Grouping implementation from Step 3
  ENDMETHOD.
ENDCLASS.

Separating the calculation from the repository/database layer is the key design decision. The calculation now accepts plain internal-table data, which makes the unit test fast and deterministic.

Step 5: ABAP Unit test

A local test class is declared with FOR TESTING. The test follows Arrange–Act–Assert and verifies both the numeric result and the business classification.

CLASS ltc_sales_summary DEFINITION FINAL
  FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.
  PRIVATE SECTION.
    METHODS totals_are_grouped FOR TESTING.
ENDCLASS.

CLASS ltc_sales_summary IMPLEMENTATION.
  METHOD totals_are_grouped.
    DATA(lt_orders) = VALUE tt_order(
      ( customer_id = '1000' sales_order = '1'
        net_value = '60000' currency = 'INR' )
      ( customer_id = '1000' sales_order = '2'
        net_value = '50000' currency = 'INR' ) ).

    DATA(lt_result) = NEW zcl_sales_summary( )->summarize( lt_orders ).
    DATA(ls_result) = lt_result[ customer_id = '1000' ].

    cl_abap_unit_assert=>assert_equals(
      act = ls_result-order_count exp = 2 ).
    cl_abap_unit_assert=>assert_equals(
      act = ls_result-total_value exp = '110000' ).
    cl_abap_unit_assert=>assert_equals(
      act = ls_result-status exp = 'High Value' ).
  ENDMETHOD.
ENDCLASS.

Add these negative tests

  • Empty input returns an empty result.
  • A customer below the threshold gets Standard.
  • Two customers produce two independent summary rows.
  • Boundary value 100000 follows the documented rule.
  • Different currencies are rejected or converted before aggregation.

ATC and quality checklist

  • No unnecessary database columns or database access inside loops.
  • Released APIs/CDS views are used for the target system.
  • Authorization, client handling and currency semantics are reviewed.
  • Method names describe intent; methods remain small.
  • Every business rule has at least one positive and one negative test.
  • Run local ATC checks and correct findings before transport.

Hands-on exercise

  1. Add a parameter iv_high_value_limit instead of hard-coding 100000.
  2. Add an order_count rule: label a customer Frequent when count is 5 or more.
  3. Create tests for 0, 1, 4 and 5 orders.
  4. Measure whether aggregation remains correct when the input order changes.
  5. Run ATC and document one improvement you made.

Interview revision

Q1. Why are inline declarations useful?
They keep a variable close to the statement that defines its type and value, reducing boilerplate. Use explicit types when an API contract or numeric precision must be obvious.

Q2. VALUE vs CORRESPONDING?
VALUE constructs a value directly. CORRESPONDING maps components with matching names and supports mapping rules.

Q3. When should REDUCE be avoided?
Avoid it when the expression becomes difficult to debug or mixes unrelated rules. Readability is more important than using the newest syntax.

Q4. Why separate database access from calculation?
It improves testability, reuse and maintainability. Unit tests can run with controlled data and no database dependency.

Q5. What makes an ABAP Unit test reliable?
It is isolated, deterministic, fast, expressive and verifies one clearly defined behaviour.

Quick course revision map

AreaModern ABAP toolUse it for
DeclarationsDATA( ), FIELD-SYMBOL( )Less boilerplate
ConstructionVALUE, NEW, CONV, CORRESPONDINGCreate and map values
DecisionsCOND, SWITCHExpression-based rules
TablesFOR, FILTER, REDUCE, GROUP BYTransform and aggregate
QualityABAP Unit, ATC, Clean ABAPSafe maintainable code

Official learning references

Your turn: Complete the exercise, run the unit tests, and share which legacy loop you would refactor first.

Post a Comment

0 Comments