ABAP Unit Test Driven Development
ABAP Unit Test Driven Development
January 27
2014
This document explains basic ABAP unit testing (Test Driven Development). Automated tests could help to recognize changes which could break the existing code. Unit testing is a technique that enables testing during development. Dedicated test classes invoke the tested program and compare the result with the expectation. ABAP Unit implements this technique. ABAP Unit is integrated both in the ABAP runtime and in the ABAP Workbench, which facilitates the writing of tests.
Contents
ABAP Unit Test Driven Development Basic Example ................................................................................. 2 Preface ...................................................................................................................................................... 2 Basic Example:....................................................................................................................................... 2 Test Class setup......................................................................................................................................... 2 Test method implementation ................................................................................................................... 3 Initial Run .................................................................................................................................................. 3 ABAP Unit Test Driven Development Basics ................................................................................................. 5 What is TDD?............................................................................................................................................. 5 Why to Write a Test First? ........................................................................................................................ 5 Test Properties .......................................................................................................................................... 6 Client Based Configuration ....................................................................................................................... 6 FOR TESTING Keyword .............................................................................................................................. 7 Class CL_AUNIT_ASSERT ........................................................................................................................... 7 ABAP Unit Test Fixture methods ................................................................................................................... 8 What is Test Fixture .................................................................................................................................. 8 Method SETUP( ) ....................................................................................................................................... 8 Method TEARDOWN( ).............................................................................................................................. 8 Method CLASS_SETUP( ) & CLASS_TEARDOWN( ) .................................................................................... 9 Demo Program .......................................................................................................................................... 9 ABAP Unit Test Global class usage .............................................................................................................. 11 Global Unit Test Class ............................................................................................................................. 11 Helper Class............................................................................................................................................. 12 Parent Unit Test ...................................................................................................................................... 12 Demo ....................................................................................................................................................... 12 Few Guidelines on using ABAP Global Test class .................................................................................... 15 Using the Test Class Code Wizard ............................................................................................................... 15 Use .......................................................................................................................................................... 15 Prerequisites ........................................................................................................................................... 15 Procedure................................................................................................................................................ 15 ABAP Unit - Advantages .............................................................................................................................. 16
Page 1
Preface
ABAP unit lets test the code at unit level like testing each piece separately. Thus making sure it would function and produce desired results when those pieces would be put together in the puzzle. Basic Example: As a starting point, lets start with a basic example so you can get introduced to the framework. This basic example has a class LCL_SUM with a method SUM. This methods responsibility is to ADD up the numbers. It takes a number as importing parameter and then adds it to itself to derive the result. This method SUM is referred as Production Method in Unit Test concept. I will cover more on the concepts in next article. The code for Production class method is like this:
* CLASS lcl_sum DEFINITION. PUBLIC SECTION. METHODS: SUM IMPORTING iv_1 TYPE i RETURNING VALUE(rv_sum) TYPE i. ENDCLASS. "lcl_sum DEFINITION * START-OF-SELECTION. * Nothing here yet * * CLASS lcl_sum IMPLEMENTATION. METHOD SUM. rv_sum = iv_1 * iv_1. ENDMETHOD. "sum ENDCLASS. "lcl_sum IMPLEMENTATION
Page 2
CLASS lcl_test IMPLEMENTATION. METHOD m_sum. ENDMETHOD. "m_sum ENDCLASS. "lcl_test IMPLEMENTATION
As you might notice here, pseudo comments and . Prior to ABAP 7.02 Pseudo comments are used to let the framework know more about the ABAP unit class. In the version 7.02 onwards, it has been replaced with addition and .
Initial Run
Now you have your test class and a test method ready. You can run the ABAP Unit from the menu Program Test Unit Test. SAP ABAP Unit Testing Page 3
When you see the ABAP Unit Results Display, you would know that there is something wrong. On the right bottom side of the screen, You would see both of the values Actual 9 vs Expected 6.
This tells me that, there is something wrong in the production method implementation. If you look closely the method implementation of the SUM, Instead of using Summation, Multiplication was used. We need to correct it and re-run the test. This time, after the code has been corrected, you would see the ABAP unit results like this:
Page 4
What is TDD?
Test Driven Development is a process in which you rely on test to validate the functionality of the production code. In this process, tests are written first, then the actual production code to pass the tests. This test would be a separate code than the production methods. The production methods are also knows as Method Under Test and the class where production code is known as Class Under Test. To develop the applications using TDD technique, we must have an automated Unit Test mechanism available in the programming language. With an introduction of the ABAP Unit framework in SAP from the ABAP release 6.20, it is now possible to use TDD technique in application development. When working with TDD, you first write an empty code block (a shell) which would finally carry your Production Code. After that you write a test to validate the functionality with using Actual and Expected. After that you re-factor your production code to pass your test. At high level the process of TDD is a Cycle. Your code would go through many iterations of writing test, refactoring production code, and test execution.
would get x/2 which is our expected value. If your actual method is to Sum the values as shown in the first section, you would know what is the expected value out of the method when you pass the inputs.
Test Properties
As you would have noticed in the example in first post, that I have used #AU followed by the text. These are test properties Risk Level and Duration. Risk Level defines the risk of the test. When executing the test, system would check the risk level against predefined risk level in the Client settings. If your test has a higher risk level, ABAP Unit framework would ignore that test and will not execute that test. You can specify one of these three possible values: Harmless The execution of this test doesnt affect any existing processes or Database. This is default setting. Dangerous (Alarming) This type of test makes changes to DB or persistent Data. Critical This type of test would make changes to Customization as well as the Persistent data. A careful look is required.
Duration Similar to Risk level, all the test would need to have expected runtime duration. ABAP Unit framework will not execute the tests with higher duration than defined in the client level configuration. For Duration, you specify these values: Short Gets executed very fast. This is default setting at the client settings. Generally < 1 minute Medium Gets executed in a bit. Little bit extra time than the short duration. In the range of 1 minute to 10 minutes Long takes a while to process the test. The execution time would be more than 10 minutes
Class CL_AUNIT_ASSERT
Class CL_AUNIT_ASSERT has various methods to test various different scenarios. Most used method is ASSERT_EQUALS. This method takes Actual and Expected values as an argument and tells the Unit Framework if the tests is passed or failed. Over the next various articles, I would leverage few of the methods from the class to validate the test. The CL_AUNIT_ASSERT class contains the following methods for checking test expectations: ASSERT_EQUALS Asserts the equality of two data objects ASSERT_DIFFERS Asserts the dissimilarity of two data objects ASSERT_BOUND Asserts the validity of the reference of a reference variable ASSERT_NOT_BOUND Asserts whether the reference of a reference variable is invalid ASSERT_INITIAL Asserts whether the data object has its initial value ASSERT_NOT_INITIAL Asserts whether the data object does NOT have its initial value ASSERT_CHAR_CP Asserts whether the character string matches the pattern ASSERT_CHAR_NP Asserts the dissimilarity of the character strings ASSERT_SUBRC Requests a specific value of the return value sy-subrc ASSERT_EQUALS_F Asserts the approximate equality of two floating point numbers of type f ASSERT_EQUALS_FLOAT Asserts the approximate equality of two floating point numbers FAIL Terminates the test with an error ABORT Terminates the test because test conditions are not met SAP ABAP Unit Testing Page 7
Method SETUP( )
Special method SETUP( ) is used to setup the common test data for the same test methods of the same test class or of the inherited test class. This method would be called before calling the test method by the ABAP Unit framework. So, basically it would be called as many times as many test methods are there in a single test class. In this method, you should generally setup your test data which can be leveraged by various different test within the same test class. Simple example, would be to setup default value for a variable, or instantiate the object for Production code.
Method TEARDOWN( )
Special method TEARDOWN( ) should be used to clear down the test data which was used by the actual test. You should use this method to clear the test data and make sure they are ready to use by the next Test method. This method would be called after calling the test method by the ABAP Unit framework. Similar to SETUP, this method would be called as many times as many test methods are there in a single test class. In this method, you should generally setup your test data which can be leveraged by various different test within the same test class. Simple example, would be to clear the product code objects or all attributes of the test class and make sure it is ready for next execution.
Page 8
Demo Program
Check out this demo program to display the use of test fixture.
REPORT ZNP_AUNIT_FIXTURE_DEMO. *&---------------------------------------------------------------------* *& Purpose - ABAP Unit fixture methods demo *&---------------------------------------------------------------------* * CLASS lcl_data DEFINITION. PUBLIC SECTION. TYPES: BEGIN OF ty_data, glacc TYPE char10, dmbtr TYPE bseg-dmbtr, END OF ty_data. TYPES: tt_data TYPE STANDARD TABLE OF ty_data. DATA: t_data TYPE tt_data. METHODS: get_sum_for_glacc IMPORTING iv_glacc TYPE char10 RETURNING VALUE(rv_amt) TYPE bseg-dmbtr. ENDCLASS. START-OF-SELECTION. * CLASS lcl_data IMPLEMENTATION. METHOD get_sum_for_glacc. DATA: ls_data LIKE LINE OF t_data. LOOP AT t_data INTO ls_data WHERE glacc = iv_glacc. rv_amt = rv_amt + ls_data-dmbtr. ENDLOOP. ENDMETHOD. "get_sum_for_glacc ENDCLASS. "lcl_data IMPLEMENTATION * CLASS lcl_test_collect DEFINITION FOR TESTING "#AU Risk_Level Harmless "#AU Duration Short . PRIVATE SECTION. DATA: o_cut TYPE REF TO lcl_data. METHODS: "lcl_data DEFINITION
Page 9
setup, teardown, test_valid_gl FOR TESTING, test_invalid_gl FOR TESTING. ENDCLASS. "lcl_test_collect DEFINITION * CLASS lcl_test_collect IMPLEMENTATION. METHOD setup. DATA: ls_data LIKE LINE OF o_cut->t_data. CREATE OBJECT o_cut. ls_data-glacc = '101'. ls_data-dmbtr = '20'. APPEND ls_data TO o_cut->t_data. ls_data-glacc = '101'. ls_data-dmbtr = '30'. APPEND ls_data TO o_cut->t_data. ls_data-glacc = '102'. ls_data-dmbtr = '40'. APPEND ls_data TO o_cut->t_data. ls_data-glacc = '101'. ls_data-dmbtr = '50'. APPEND ls_data TO o_cut->t_data. ENDMETHOD. "setup METHOD teardown. CLEAR o_cut. ENDMETHOD. "teardown METHOD test_valid_gl. DATA: lv_result_amt TYPE bseg-dmbtr. lv_result_amt = o_cut->get_sum_for_glacc( '101' ). cl_aunit_assert=>assert_equals( EXP = 100 act = lv_result_amt msg = 'Total is incorrect' ). ENDMETHOD. "test_valid_gl METHOD test_invalid_gl. DATA: lv_result_amt TYPE bseg-dmbtr. lv_result_amt = o_cut->get_sum_for_glacc( '999' ). cl_aunit_assert=>assert_equals( EXP = 0 act = lv_result_amt msg = 'Total is incorrect' ). ENDMETHOD. ENDCLASS. "test_invalid_gl "lcl_test_collect IMPLEMENTATION
AS rule of TDD you start with empty production method and initial test.
Page 10
After implementing the logic and re-factoring the test, you would notice your test is getting successful.
Page 11
Once the class is created, you can specify the Runtime Limit and Risk Level.
You might have noticed that I have created class as Abstract Instantiation. Before we talk about that, lets see different type of usage of Global Test class.
Helper Class
These class would contain the methods which would be used or leveraged in building up part of test fixture. Although, these type of class would be tagged with FOR TESTING, you may not create any test method as such. This class may also not contain any full test fixture method, but it would have smaller helper methods to be part of fixture.
Demo
In his Demo, I have the the logic to build a packet from a bigger dataset. Global unit test class ZCL_DEMO_AUT
CLASS ZCL_DEMO_AUT DEFINITION PUBLIC ABSTRACT CREATE PUBLIC
Page 12
FOR TESTING "#AU Duration Short "#AU Risk_Level Harmless . *"* public components of class ZCL_DEMO_AUT *"* do not include other source files here!!! PUBLIC SECTION. *"* protected components *"* do not include other PROTECTED SECTION. DATA O_CUT TYPE REF TO METHODS BUILD_ITAB_ALL of class ZCL_DEMO_AUT source files here!!! ZCL_DEMO_PACKET . .
Page 13
With empty implementation in MAKE_PACKET( ), it the test would fail as expected doesnt match with actual result. So, add the implementation to create a packet.
METHOD make_packet. DATA: lv_from TYPE i. DATA: lv_to TYPE i. lv_to = v_number_of_packet * v_packet_size. lv_from = lv_to - v_packet_size + 1. APPEND LINES OF t_data FROM lv_from TO lv_to TO rt_packet. ENDMETHOD.
Page 14
Use
You use the Test Class Code Wizard to create a skeleton test class. The wizard is available for class pools and function groups. You use the wizard for: Creating skeleton test classes for methods of global and local classes. Creating skeleton test classes for function modules. Adding new test methods to existing test classes.
Prerequisites
The analysis of the program you are testing is performed on base of the active version. Make sure you have activated the latest version before opening the Test Class Generator.
Procedure
To open the wizard, on the initial screen of the Class Builder or the Function Builder, choose Utilities TestClass Generator. This menu is only available in editing mode. 1. On the first screen, define a new test class or to update an existing one. 2. On the next screen, choose the methods or function that you want to test. 3. In the dialog box that appears, confirm your choices.
Page 15
Another major advantage of unit tests is that they are written during implementation. This ensures that testing cannot be postponed or cancelled. It is even possible to write the unit tests before the implementation of the program under test.
Page 16