Page tree
Skip to end of metadata
Go to start of metadata

ABAP Unit

Motivation

Testing is a substantial part of the program development process. Tests verify the intended program behaviour. In that sense also debugging or simple text traces are tests. Nevertheless these two methods require human judgement. This soon limits the test possibilities when coming to more complex test scenarios: debug information must be checked step by step and text output very easily becomes so voluminous that they are hardly manageable ("scroll-blindness"). A long-term benefit from testing is only achievable by automation. A unit test tool solves the mentioned problems with developer tests. ABAP Unit is the new unit test tool for ABAP. Tests can be conveniently grouped into test tasks. Test results are condensed and become at once evident. Test tasks can be performed automated.

First Steps with ABAP Unit

Implementation

Tests are defined and implemented as local classes inside a main program.

  1. Define a local class with the extension "FOR TESTING" and no constructor with parameters.
  2. Therein define methods with no parameters and the extension "FOR TESTING".
  3. Implement test code inside this method and verify the expected state using assert methods from the utility class "CL_AUNIT_ASSERT".
    1. In releases with SAP_BASIS >= 7.02 CL_ABAP_UNIT_ASSERT offers more methods.
Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
*----------------------------------*
*       CLASS ltc_Wallet DEFINITION
*------------------------------------*
*
*-----------------------------------*
CLASS LTC_WALLET DEFINITION FOR TESTING. "#AU Risk_Level Harmless
  PRIVATE SECTION.
    METHODS CHECK_LIQUIDITY FOR TESTING.
ENDCLASS.                    "ltc_Wallet DEFINITION
*----------------------------------*
*       CLASS ltc_Wallet IMPLEMENTATION
*------------------------------------*
*
*------------------------------------*
CLASS LTC_WALLET IMPLEMENTATION.
  METHOD CHECK_LIQUIDITY.
    DATA:
      MY_WALLET TYPE REF TO CL_WALLET,
      LIQUIDITY TYPE I.
    CREATE OBJECT MY_WALLET.
    LIQUIDITY = MY_WALLET->GET_LIQUIDITY( ).
    CL_AUNIT_ASSERT=>ASSERT_EQUALS(
      ACT = LIQUIDITY
      EXP = 0
      MSG = 'New wallet assumed empty' ).
    MY_WALLET->PUT_IN( EUROS = 12 ).
    CL_AUNIT_ASSERT=>ASSERT_EQUALS(
      ACT = MY_WALLET->LIQUIDITY
      EXP = 12
      MSG = 'As many euros as put in before' ).
  ENDMETHOD.                    "check_Liquidity
ENDCLASS.                    "ltc_Wallet IMPLEMENTATION

Note: You might wonder why the test method is defined as a private method. The answer is that all test classes grant friendship to the ABAP Unit test driver. So you should use the visibility of test methods to express if the test method should only be performed when running the respective test class (private), if it should also be performed when running test classes derived from this test class (protected) or if you want to allow delegation, i.e. to offer the execution from other test classes (public). The most common case is certainly the exclusive use of a test method in the context of its test class, so in case of doubt define the test methods in the private section.

Test Simplification: Common Test Objects, Test-Fixture

Tests usually employ well-known, prepared objects. The complete set of such objects is called the "test fixture". Easily the set up of the test fixture can become more laborious as the actual testing itself. Hence the test framework offers two special test methods, which serve for the "setup" and the "teardown" of the test fixture. In continuation of the above example one might need to employ two test wallets with different amounts of money:

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
*-----------------------------------------*
*       CLASS lcl_2nd_Wallet_Test DEFINITION
*-------------------------------------*
*
*-----------------------------------*
CLASS LCL_2ND_WALLET_TEST DEFINITION FOR TESTING. "#AU Risk_Level Harmless

  PRIVATE SECTION.
    METHODS:
      SETUP,
      CHECK_WITHDRAWAL FOR TESTING,
      CHECK_REMAINDER   FOR TESTING.
    DATA:
      F_WALLET    TYPE REF TO CL_WALLET,
      F_BALANCE   TYPE I.
ENDCLASS.                    "lcl_2nd_Wallet_Test DEFINITION
*------------------------------------------*
*       CLASS lcl_2nd_Wallet_Test IMPLEMENTATION
*---------------------------------*
*
*----------------------------------------*
CLASS LCL_2ND_WALLET_TEST IMPLEMENTATION.
  METHOD SETUP.
    CREATE OBJECT ME->F_WALLET.
    ME->F_BALANCE = 20.
    ME->F_WALLET->PUT_IN( F_BALANCE ).
  ENDMETHOD.                    "setup
  METHOD CHECK_WITHDRAWAL.
    DATA:
      LIQUIDITY TYPE I.
    ME->F_WALLET->TAKE_OUT( ME->F_BALANCE ).
    LIQUIDITY = ME->F_WALLET->GET_LIQUIDITY( ).
    CL_AUNIT_ASSERT=>ASSERT_EQUALS(
      ACT = LIQUIDITY
      EXP = 0
      MSG = 'Higher debt than liquidity!' ).
  ENDMETHOD.                    "check_Withdrawal
  METHOD CHECK_REMAINDER.
    DATA:
       WITHDRAW  TYPE I,
       LIQUIDITY TYPE I.
    WITHDRAW = ME->F_BALANCE - 4.
    ME->F_WALLET->TAKE_OUT( WITHDRAW ).
    LIQUIDITY = ME->F_WALLET->GET_LIQUIDITY( ).
    CL_AUNIT_ASSERT=>ASSERT_EQUALS(
      ACT = LIQUIDITY
      EXP = 4
      MSG = 'Reminder after withdrawal wrong!' ).
  ENDMETHOD.                    "check_Remainder
ENDCLASS.                    "lcl_2nd_Wallet_Test IMPLEMENTATION

Note the private definition of the fixture method "setup". Fixture methods always apply to their test classes and must neither be inherited by derived test classes nor be called explicitely from other test code. The (befriended) test driver calls the fixture methods in a prescribed order.

Test Execution and Test Task Creation

Within the development environment all tests for one program frame can be started using the command "Unit test" under the menu "Execute". The main program is either a class pool (SE24) a function group (SE37) or a report (SE38).

Collections of tests can be run by using the code inspector (transaction SCI). There under dynamic tests, you can add unit tests to your test variant.

Result Display

The result display is organized in three detail levels. On the left side the test task is presented hierarchically. A test task contains main programs, which contain test classes. Test methods are part of test classes. Select (double click) a branch of this test task tree. On the right hand side you will find all problems with type and message corresponding to your selection. If you select a message in the upper right window frame, you get detail information for this problem in the lower window: a problem analysis and possibly the failure stack where the problem occurred. You can navigate to the corresponding source by double clicking the failure stack line.

10 Comments

  1. Former Member

    How to test private components of global Classes?

    To test private or protected components of a global class (defined in SE24), simply add the following lines to the local definitions (SE24 -> Goto -> Class-local types -> Local Class Definitions/Types) of the global class to be tested: 

    CLASS lcl_test_class DEFINITION DEFERRED. * change definition of global class to state LCL_TEST_CLASS as a friendCLASS zcl_your_global_class_2_be_tested DEFINITION LOCAL FRIENDS lcl_test_class.  * regular definition of LCL_TEST_CLASSCLASS lcl_test_class DEFINITION FOR TESTING....ENDCLASS.
    

    Now the test methods defined in your local test class can access all components (attributes, methods, ...) defined as private or protected of the global class to be tested.

    Happy Hackin9!
    --MIKE

  2. Unknown User (nbd5llv)

    how to startup debug model ? can i use setp debug?

  3. Unknown User (g99ajum)

    Other language NUnit test frameworks similar to ABAP Unit (AUnit) commonly have project extensions for storing test results. On large applications these are useful for the unit level regression (did a new change break any existing functions). History of test results, help narrow down the nature of a current failure by answering the question of 'When did this break?' or when did it last pass? In systems dependent upon outside components the history can provide a pattern for occasional failures due to factors outside the system under test.

    I see that ABAP unit test results can be added into the Code Inspector under the Check Variant. 

    1. Is it common to use the Code Inspector (SCI) to store AUnit test results?

    2. Is it common to use Code Inspector Object variants to collect individual AUnit tests for a regresssion style 'TestSuite'?

    3. What reporting or tools exists for Code Inspector history?

  4. I will propose to add this reference: The basics of unit testing

    JNN

  5. Former Member

    Can ABAP test only be used for units which return mathematical or string output ?  Also how is the practically used in a business scenario where we are creating a report ?. e.g say open orders report.

  6. Hi, very interesting document.

    Just do inform what I discovered today looking at the class documentation of CL_AUNIT_ASSERT: 

    Important Note

    This class has been superseded by CL_ABAP_UNIT_ASSERT. There is no urgent need to change existing use cases. But it is strongly recommended not to add further use cases.

  7. Is it possible to check , if an instance is bound or not? 

    for my method returning is an instance of  a class. 

    Or this is only for checking /comparing values. 

  8. Hi,

    Is it possible to write AUNITS for the SE38 report ?

    1. Yes it is possible to implement AUNITS for SE38 report,

      there are lot of information available online for the same. 

      1. Thank you for your response. Could you please help me to get one example ?