ABAP Unit & Test Doubles

Test classes are local classes in the test classes include of a global class (or in a report) marked FOR TESTING:

37.1 ABAP Unit basics

Test classes are local classes in the test classes include of a global class (or in a report) marked FOR TESTING:

Run with Ctrl+Shift+F10 in ADT or *Module Test* (Ctrl+Shift+F10/menu) in SAP GUI; coverage via *Run As → ABAP Unit Test With Coverage*.

CLASS ltc_calculator DEFINITION FINAL FOR TESTING
  DURATION SHORT
  RISK LEVEL HARMLESS.

  PRIVATE SECTION.
    DATA mo_cut TYPE REF TO zcl_calculator.        " class under test
    METHODS setup.
    METHODS add_two_numbers FOR TESTING.
    METHODS divide_by_zero_raises FOR TESTING.
ENDCLASS.

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

  METHOD add_two_numbers.
    cl_abap_unit_assert=>assert_equals( exp = 5 act = mo_cut->add( iv_a = 2 iv_b = 3 )
                                        msg = 'Addition failed' ).
  ENDMETHOD.

  METHOD divide_by_zero_raises.
    TRY.
        mo_cut->divide( iv_a = 1 iv_b = 0 ).
        cl_abap_unit_assert=>fail( 'Exception expected' ).
      CATCH zcx_division_by_zero.
        " expected
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

37.2 Fixture methods and assertions

class_setup (static) Once before all tests of the class Before each test method After each test method class_teardown (static) Once after all tests

Assertions (CL_ABAP_UNIT_ASSERT): assert_equals, assert_differs, assert_true, assert_false, assert_initial, assert_not_initial, assert_bound, assert_not_bound, assert_subrc, assert_char_cp, assert_table_contains, assert_number_between, fail, skip. Test attributes: RISK LEVEL HARMLESS | DANGEROUS | CRITICAL, DURATION SHORT | MEDIUM | LONG.

37.3 Dependency injection and test doubles

Design for testability: depend on interfaces and inject implementations.

Test with a hand-written fake or the ABAP OO test double framework:

INTERFACE zif_order_repository.
  METHODS get_order IMPORTING iv_id TYPE zorders-order_id RETURNING VALUE(rs_order) TYPE zorders.
ENDINTERFACE.

CLASS zcl_order_pricing DEFINITION PUBLIC CREATE PUBLIC.
  PUBLIC SECTION.
    METHODS constructor IMPORTING io_repo TYPE REF TO zif_order_repository OPTIONAL.
    METHODS discounted_amount IMPORTING iv_id TYPE zorders-order_id
                              RETURNING VALUE(rv_amount) TYPE zorders-amount.
  PRIVATE SECTION.
    DATA mo_repo TYPE REF TO zif_order_repository.
ENDCLASS.

CLASS zcl_order_pricing IMPLEMENTATION.
  METHOD constructor.
    mo_repo = COND #( WHEN io_repo IS BOUND THEN io_repo ELSE NEW zcl_order_repository_db( ) ).
  ENDMETHOD.
  METHOD discounted_amount.
    DATA(ls_order) = mo_repo->get_order( iv_id ).
    rv_amount = COND #( WHEN ls_order-amount > 1000 THEN ls_order-amount * '0.9' ELSE ls_order-amount ).
  ENDMETHOD.
ENDCLASS.
METHOD big_orders_get_discount.
  DATA lo_repo TYPE REF TO zif_order_repository.
  lo_repo ?= cl_abap_testdouble=>create( 'ZIF_ORDER_REPOSITORY' ).
  cl_abap_testdouble=>configure_call( lo_repo )->returning( VALUE zorders( amount = 2000 ) ).
  lo_repo->get_order( '0000000001' ).                     " records the configuration

  DATA(lo_cut) = NEW zcl_order_pricing( lo_repo ).
  cl_abap_unit_assert=>assert_equals( exp = 1800 act = lo_cut->discounted_amount( '0000000001' ) ).
ENDMETHOD.

37.4 Test environments for database, CDS, and more

ABAP SQL test double Database tables / views used in ABAP SQL CDS test double Dependencies of a CDS view under test Function module test double RAP BO test double

CL_BOTD_TXBUFDBL_BO_TEST_ENV, CL_BOTD_MOCKEMLAPI_BO_TEST_ENV EML calls to RAP BOs AUTHORITY-CHECK results Test seams (legacy code) TEST-SEAM / TEST-INJECTION Replace code blocks in tests (zorders_tt stands for a table type of ZORDERS.)

CLASS ltc_repo DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
  PRIVATE SECTION.
    CLASS-DATA go_env TYPE REF TO if_osql_test_environment.
    CLASS-METHODS class_setup.
    CLASS-METHODS class_teardown.
    METHODS setup.
    METHODS reads_order FOR TESTING.
ENDCLASS.

CLASS ltc_repo IMPLEMENTATION.
  METHOD class_setup.
    go_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( 'ZORDERS' ) ) ).
  ENDMETHOD.
  METHOD class_teardown.
    go_env->destroy( ).
  ENDMETHOD.
  METHOD setup.
    go_env->clear_doubles( ).
    DATA(lt_data) = VALUE zorders_tt( ( order_id = '0000000001' amount = 50 ) ).
    go_env->insert_test_data( lt_data ).
  ENDMETHOD.
  METHOD reads_order.
    DATA(ls_order) = NEW zcl_order_repository_db( )->zif_order_repository~get_order( '0000000001' ).
    cl_abap_unit_assert=>assert_equals( exp = 50 act = ls_order-amount ).
  ENDMETHOD.
ENDCLASS.