abap unit test driven development

21
SAP ABAP Unit Testin g 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.

Upload: shadydogv5

Post on 20-Oct-2015

85 views

Category:

Documents


4 download

DESCRIPTION

ABAP Unit Test Driven Development

TRANSCRIPT

January 27

2014This 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.

ContentsABAP 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

SAP ABAP Unit Testing Page 1

ABAP Unit - Advantages.............................................................................................................................16

ABAP Unit Test Driven Development – Basic Example

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, let’s 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 method’s 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. "sumENDCLASS. "lcl_sum IMPLEMENTATION

Test Class setup

To declare a class which acts as test class, you would need to add the keyword FOR TESTING when defining the class. This addition separates this class from the production code. Similarly, you need to add the keyword FOR TESTING to the method to make a test method.

*CLASS lcl_test DEFINITION FOR TESTING "#AU Risk_Level Harmless "#AU Duration Short

SAP ABAP Unit Testing Page 2

. PUBLIC SECTION. METHODS: m_sum FOR TESTING.ENDCLASS. "lcl_test DEFINITION*CLASS lcl_test IMPLEMENTATION. METHOD m_sum. ENDMETHOD. "m_sumENDCLASS. "lcl_test IMPLEMENTATION

As you might notice here, pseudo comments #AU Risk_Level and #AU Duration. 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 RISK LEVEL and DURATION.

Test method implementation

In this test method, what you need to do is – Test the production code. So, to be able to test method SUM of LCL_SUM, you would need to instantiate an object reference to LCL_SUM, call the method SUM sending the dummy value. Based on the Dummy value, the method would send you the result – the actual result from the method. Based on Dummy value, you know what would be expected value. E.g. If you pass number 3 to SUM method, it would give you the result of 6 as it is adding 3 to 3.

Once you receive the actual result from the production code or method under test, you need to compare the results. If the actual vs expected are not matching, you need to let the ABAP Unit framework know that something is wrong with the actual vs Expected. To be able to do this you can use the methods from the class CL_AUNIT_ASSERT. For this demo purpose, we would use method ASSERT_EQUALS.

*CLASS lcl_test IMPLEMENTATION. METHOD m_sum. DATA: o_cut TYPE REF TO lcl_sum. DATA: lv_result TYPE i.* CREATE OBJECT o_cut. lv_result = o_cut->sum( 3 ).* cl_aunit_assert=>assert_equals( EXP = 6 act = lv_result msg = 'something wrong' ). ENDMETHOD. "m_sumENDCLASS. "lcl_test IMPLEMENTATION

SAP ABAP Unit Testing Page 3

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.

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.

SAP ABAP Unit Testing Page 4

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:

ABAP Unit Test Driven Development Basics

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.

Step would be:

Write a Test Make Test Pass Refactoring

SAP ABAP Unit Testing Page 5

Why to Write a Test First?

When you start writing the test, you would start thinking of various aspects of requirement and start designing the production methods accordingly – Like defining the Attributes or parameters to the method. You would also think on the expected results based on the inputs e.g. If we pass x value, we 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 doesn’t 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

Specify test properties, As of Release 700

CLASS Abap_Unit_Testclass DEFINITION FOR TESTING "#AU Duration Short "#AU Risk_Level Harmless.

Specify test properties, As of Release 702 (Release 7.0 Enhancement Pack 2)

CLASS Abap_Unit_Testclass DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.

Client Based Configuration

SAP ABAP Unit Testing Page 6

You can maintain the client based configuration for switch off Unit Test, allowed preference for Risk level and Duration in the transaction SAUNIT_CLIENT_SETUP. You must not change the settings on the fly as all of your tests may become non-executable because they are having different Risk Level and Duration than defined in the settings. Setting screen looks similar to this:

FOR TESTING Keyword

The addition Testing is important when defining the test class. If you omit the addition, your class would be considered as a simple production class. The FOR TESTING addition makes it a test class. You would also need at least one method with addition FOR TESTING.

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 objectsASSERT_DIFFERS Asserts the dissimilarity of two data objectsASSERT_BOUND Asserts the validity of the reference of a reference variableASSERT_NOT_BOUND Asserts whether the reference of a reference variable is invalidASSERT_INITIAL Asserts whether the data object has its initial valueASSERT_NOT_INITIAL Asserts whether the data object does NOT have its initial valueASSERT_CHAR_CP Asserts whether the character string matches the patternASSERT_CHAR_NP Asserts the dissimilarity of the character stringsASSERT_SUBRC Requests a specific value of the return value sy-subrc

SAP ABAP Unit Testing Page 7

ASSERT_EQUALS_F Asserts the approximate equality of two floating point numbers of type fASSERT_EQUALS_FLOAT

Asserts the approximate equality of two floating point numbers

FAIL Terminates the test with an errorABORT Terminates the test because test conditions are not met

ABAP Unit Test Fixture methods

What is Test Fixture

Test fixture is the test configuration like test data or test objects. This data would be used within the test methods. Fixture would be executed before the actual test method gets executed. So when the test is getting performed, the test data or test objects setup in fixture method can be used.

In ABAP, the test fixture is achieved using these predefined methods. These methods would be called automatically by ABAP framework if they exist in the test class.

SETUP – Instance method SETUP would be called before each test within the test class TEARDOWN – In contrary to SETUP, instance method TEARDOWN would be called after each

testwithin the test class CLASS_SETUP – Similar to SETUP, static method CLASS_SETUP would be used to set up the data

once before the first test in the class gets executed CLASS_TEARDOWN – Like TEARDOWN, static method TEARDOWN would be used to clear the

data once after the last test in the class gets executed

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.

SAP ABAP Unit Testing Page 8

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.

Method CLASS_SETUP( ) & CLASS_TEARDOWN( )

Method CLASS_SETUP( ) is a static method. Set up the test data and save it into some temporary variable. We can use these test data into the SETUP method. The purpose of CLASS_SETUP is to set up the same data like a configuration which would be used by all test methods but NONE of the test method would be modifying it.

Static method CLASS_TEARDOWN would to make sure you clear up all the data and related attributes used in the test class before leaving the class.

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. "lcl_data DEFINITION

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

SAP ABAP Unit Testing Page 9

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: 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. "test_invalid_glENDCLASS. "lcl_test_collect IMPLEMENTATION

AS rule of TDD you start with empty production method and initial test.

SAP ABAP Unit Testing Page 10

After implementing the logic and re-factoring the test, you would notice your test is getting successful.

ABAP Unit Test Global class usage

Global Unit Test Class

When you create a class in SE24 or in SE80, you can specify the category of the class. Here you have an option to make any class as Global Unit Test class by selecting Test Class (ABAP Unit).

Once the class is created, you can specify the Runtime Limit and Risk Level.

SAP ABAP Unit Testing Page 11

You might have noticed that I have created class as Abstract Instantiation. Before we talk about that, let’s 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.

Parent Unit Test

This type of class may contain at least one test method. It may also contain a fixture method. You can inherit your local test class from this global class. You can create a Global Unit Test class with few test methods and reuse that while defining the local test class. Since, you won’t be able to instantiate the object as well as you don’t want to have lot of programs using the same class, you should create the class as Abstract class.

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 FOR TESTING "#AU Duration Short

SAP ABAP Unit Testing Page 12

"#AU Risk_Level Harmless .

*"* public components of class ZCL_DEMO_AUT*"* do not include other source files here!!!PUBLIC SECTION.

*"* protected components of class ZCL_DEMO_AUT*"* do not include other source files here!!!PROTECTED SECTION. DATA O_CUT TYPE REF TO ZCL_DEMO_PACKET . METHODS BUILD_ITAB_ALL .

Method BUILD_ITAB_ALL implementation

METHOD build_itab_all.

DATA: lv_string TYPE STRING. DO 10 TIMES. lv_string = sy-INDEX. CONCATENATE 'Line -' lv_string INTO lv_string. APPEND lv_string TO o_cut->t_data. ENDDO.

ENDMETHOD.

Class Under test – production class

CLASS ZCL_DEMO_PACKET DEFINITION PUBLIC FINAL CREATE PUBLIC .

*"* public components of class ZCL_DEMO_PACKET*"* do not include other source files here!!!PUBLIC SECTION.

DATA V_PACKET_SIZE TYPE I . DATA V_NUMBER_OF_PACKET TYPE I . DATA T_DATA TYPE TREXT_STRING .

METHODS MAKE_PACKET RETURNING VALUE(RT_PACKET) TYPE TREXT_STRING .

Local class definition inheriting from ZCL_DEMO_AUT

*"* use this source file for any type declarations (class*"* definitions, interfaces or data types) you need for method*"* implementation or private method's signature

CLASS lcl_test_packet DEFINITION INHERITING FROM zcl_demo_Aut FOR TESTING "#AU Duration Short "#AU Risk_Level Harmless .

SAP ABAP Unit Testing Page 13

PRIVATE SECTION. METHODS: setup, test_packet_2 FOR TESTING.

ENDCLASS.

Local test class implementation

*"* local class implementation for public class*"* use this source file for the implementation part of*"* local helper classes

CLASS lcl_test_packet IMPLEMENTATION. METHOD setup. CREATE OBJECT me->o_cut. me->build_itab_all( ). me->o_cut->v_packet_size = 3. me->o_cut->v_number_of_packet = 2. ENDMETHOD. "setup METHOD test_packet_2.

DATA: lt_result_itab TYPE trext_string. DATA: lt_exp_itab TYPE trext_string.

APPEND LINES OF o_cut->t_data FROM 4 TO 6 TO lt_exp_itab.

lt_result_itab = o_cut->make_packet( ). cl_aunit_assert=>assert_equals( EXP = lt_exp_itab act = lt_result_itab msg = 'Unable to create proper packet' ).

ENDMETHOD. "test_packet_2ENDCLASS. "lcl_test_packet IMPLEMENTATION

With empty implementation in MAKE_PACKET( ), it the test would fail – as expected doesn’t 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.

Few Guidelines on using ABAP Global Test class

SAP ABAP Unit Testing Page 14

Refrain of using the Global test class as Parent Test class. This would get executed in all the test classes where ever the local class is inheriting the class. It may be unnecessary.

Make your helper class as Test class as well by adding the FOR TESTING as you don’t want it to run in production

Use test class to build up smaller chunk of the text fixtures which can be reused in your various test cases

All instance methods are by default for testing. So, make sure you remove it for testing as you don’t want to create test methods in the Global test class

Using the Test Class Code Wizard

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.

ABAP Unit - Advantages

SAP ABAP Unit Testing Page 15

Testing is a substantial part of the program development process. Tests verify the intended program behavior. Debugging or simple text traces are also tests. Nevertheless, these methods require human judgment, which limits the test possibilities when it comes to more complex test scenarios: debug information must be checked step by step and text output becomes voluminous and hardly manageable. A long-term benefit from testing is only achievable by automation.

ABAP Unit solves these problems. It is integrated into the ABAP runtime system and the ABAP Workbench, so that writing and executing tests becomes a part of the development process.

Testing small portions of code has many advantages, including the following:

It is easy to locate the problem. The area where the error can be located is minimal. A mistake in one test cannot cause other mistakes in other tests of the program, because of the

isolation requirement. You require less effort to construct a simple test than to create a complex test scenario.

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.

SAP ABAP Unit Testing Page 16