ABAP Unit

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".
class ltc_Wallet definition for testing.

  private section.

    methods check_Liquidity for testing.

endclass. 

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.

endclass.

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:

class lcl_2nd_Wallet_Test definition for testing.
 
  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.

class lcl_2nd_Wallet_Test implementation.

method setup.
  create object f_Wallet.
  f_Balance = 20.
  f_Wallet->put_In( f_Balance ).
endmethod.

method check_Withdrawal.
  data:
    liquidity type i.

  f_Wallet->take_Out( f_Balance ).
  liquidity = f_Wallet->get_Liquidity( ).

  cl_Aunit_Assert=>assert_Equals(
    act = liquidity
    exp = 0
    msg = 'Higher debt than liquidity!' ).

endmethod.

method check_Remainder. 
  data:
     withdraw  type i,
     liquidity type i.

  withdraw = f_Balance - 4. 
  f_Wallet->take_Out( withdraw ). 
  liquidity = f_Wallet->get_Liquidity( ).

  cl_Aunit_Assert=>assert_Equals(
    act = liquidity
    exp = 4
    msg = 'Reminder after withdrawal wrong!' ).

endmethod.
endclass.

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 Presentation

The result presentation is designed 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.

Further Reading

ABAP Unit - Best Practices

A Spotlight on ABAP Unit
Part 1
Part 2
Part 3
Part 4
Part 5

TDD - Test Driven Development
Wikipedia: Test Driven Development
Wikipedia: Mock Objects
Gerard Meszaros: xUnit Patterns
Steve Freeman et al: Mock Rules, Not Object

Labels

abapobjects_abapunit abapobjects_abapunit Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.