© Rehan Zaidi 2019
R. ZaidiSAP ABAP Objectshttps://doi.org/10.1007/978-1-4842-4964-2_7

7. ABAP Unit Test-Driven Development

Rehan Zaidi1 
(1)
Dubai, United Arab Emirates
 
An important topic that remains to be discussed is testing the methods and code that we write. SAP provides the unit test framework embedded in ABAP. In this chapter, we learn in detail about the following topics:
  • Unit testing advantages

  • Defining unit classes

  • Exception handling in unit testing

  • Using the unit test browser

We will start with a brief explanation of testing and its various types. We will then see what unit testing and test-driven development are. We will also cover the advantages of unit testing. We will then cover creation of the unit test method and classes in detail and the relevant coding and class and methods involved. Finally, we will see a full-fledged programming demo.

We cover how to execute the unit test and check results with and without the Code Inspector. We end the chapter with a note on the unit test browser that is available for searching and displaying unit test classes residing in the ABAP system.

Testing Need and Phases

Before going into the details of unit testing, let’s first see why the need for testing arises in program development.

Within a project’s development lifecycle, there may be a number of stages and phases. There is a need to test programs or products in both the development and integration stages.

Testing products is a necessary activity and has a number of advantages:
  • There is less chance of bugs and problems arising in the product. Testing allows us to make a more accurate and better quality product for our customers.

  • Good testing done in the early stages is more cost effective than later testing.

  • Testing improves customers’ confidence in the products.

Before moving forward, let’s discuss the various levels of testing. There are a number of levels in software testing:
  1. 1.

    Unit testing. This is the initial testing level. Basic (individual) units of codes are checked in order to ensure they work as required. Each code portion is subjected to a set of test scenarios or cases. Unit testing may be done manually or be automated. However, developers usually perform automated tests.

     
  2. 2.

    Integration component testing. As the name indicates, this checks the integration testing of different units (or modules) that have been unit tested. These are grouped in a number of ways to confirm the correctness of integration and communication.

     
  3. 3.

    System/UI testing. This emphasizes the UI (User Interface) and can be done manually or via automated tools. It confirms the characteristics and state of the user interface elements. This may be done by sets of test cases.

     
  4. 4.

    Acceptance testing. This is based on the Quality Assurance (QA) approach and determines which features of an application work (or do not work). The team has the option to discover and test the applications(s) in real-time. Usually, test cases are not made in advance. While testing, the team decides which application is next to be tested and how many days are to be given to a feature during the testing phase.

     

Note

Other than unit testing, the internal details of an application are visible as a “black box” to the test team during the testing stage.

Basics of ABAP Unit Test Driven Development

The unit test ABAP unit framework provides an automated mechanism within the ABAP programming language for carrying out test driven development. In test-based development, we first write a code block carrying the production code. We then write tests to check the correctness, by comparing the Expected Value and the Actual value returned. Finally, we refactor code so that it passes the test. All this may occur in cycles, i.e. our code may go through many cycles and iterations, such as test writing, changing production code, and then test execution (see Figure 7-1).
../images/478428_1_En_7_Chapter/478428_1_En_7_Fig1_HTML.jpg
Figure 7-1

Test driven development cycle

While writing the test code, we must keep in mind several aspects pertaining to the requirements, code test, and production methods. These aspects include definition of the attributes and the method parameters.

As mentioned, there are two separate methods—test methods and production methods. The production methods are also called the methods under test, whereas the class where the production code resides is known as the class under test.

Every time we want to check a small unit and its functioning is working as normal, we use unit testing. A unit is simply termed the smallest testable part of an application. This can be a class or a method, which can be separated from the other code while being checked if it functions correctly.

You should also consider and manually compute the expected result corresponding to the respective inputs. For example, if you have a method for doubling a number, we can first expected value (2 ∗ X ). We can then compare this with the actual value computed by the program code.

We specify the Risk Level and Duration test properties while designing the test.

Risk level, as the name indicates, is the risk of the test.

While running the tests, SAP checks the risk level with the level that’s predefined within the client setting. If our test has a bigger risk level, the ABAP framework will not run the test in question. For risk levels, one of the three following values may be set:
  • Harmless. As the name indicates, executing this test will not affect a process and will not make any changes to the database. This is the default.

  • Dangerous/alarming. Such tests change data in the database.

  • Critical. These are the critical tests and changes that customize the database/persistent data.

As far as Duration goes, the ABAP unit framework does not run tests with a higher duration than that specified in the client level configuration in the SAUNIT_CLIENT_SETUP transaction.

The Duration may have the following values:
  • Short. Refers to tests that run very quickly (default setting at the client level). Typically, this is less than 60 seconds.

  • Medium. Refers to tests running slightly longer than short values. These lie in the range of 60 to 600 seconds.

  • Long. These tests take a considerable amount of time to execute; more than 600 seconds.

The unit test class definition has the following form.
CLASS Abap_Unit_Testclass DEFINITION FOR TESTING
   "#AU Duration Short
   "#AU Risk_Level Harmless
.
As of Release 702 (Release 7.0 Enhancement Pack 2), the unit class definition has the following form:
CLASS Abap_Unit_Testclass DEFINITION FOR TESTING
   DURATION SHORT
   RISK LEVEL HARMLESS

Unit Test Benefits

Unit tests have a number of advantages. Unit tests:
  • Are very fast in execution. Many thousands of tests can be executed per second.

  • Emphasize small portions of the product.

  • Are written separately from the production code.

Unit tests cover 75 to 85 percent of the code. They are fast and accurate. Unit tests help point to the exact location where the code is buggy. Consistent unit test repetition helps make an application more stable and perform better.

In contrast to the other tests mentioned earlier, when using unit testing you need to have a good knowledge of system architecture. Unit testing is referred to gray box (or white box) testing and are defined by the ABAP developer.

Like other programming languages, ABAP has a unit testing framework. Within the framework, the processes needed for testing are embedded into the IDE. This allows developers to run unit tests in each compilation of the test program.

Unit tests do not interact with external coding or external systems. They are executed in a secluded environment. Unit tests are typically run on test methods, which reside in test classes.

As a developer you should make sure that you program in a manner that makes it fast and easy for you to create unit tests.
  • Unit testing is applicable in situations where carrying out tests serves a definite purpose or meaning. Usually, the business layer is good for executing tests and is where unit testing mainly focuses.

  • You must code automated tests as well as testable code. After executing the unit tests, you can amend the source code in order to fix bugs and bring the code to a testable state.

  • You have to ensure that when a correction is done in one unit that no other code units are affected.

A test method can have a number of input (importing) parameters and usually a single output parameter. You can use transactions SE38 and SE80 to create an ABAP unit. You also have another option for doing unit testing in the ABAP Unit Framework, which is via the Eclipse IDE. This is contained in the ABAP Development Tools (ADT), so you need to only install the respective add-on in Eclipse. We discuss unit test using Eclipse in Chapter 8.

Within the “then” portion of the test method, the resulting value is checked by comparing the expected value with the actual value the method under test returns. If the two results differ, the ABAP Test Framework issues an error. Say we have a class called CL_AUNIT_ASSERT, which provides a number of utility methods. For comparison purposes, we use the ASSERT_EQUALS method of the CL_AUNIT_ASSERT class .

The main challenge is to figure out the cases to cover during testing. Unit tests are made by the developer, since the developer who coded the product is the best person to know how the functionality can be tested. When we do ample testing of the small parts of our product, there will be less time and effort needed in debugging and fixing issues later on.

Demo Example

As mentioned earlier, the ABAP Unit Framework allows developers to test program coding at the unit level, i.e., check each unit code independently and separately without worrying about the entire solution. Checking these smaller units ensures that when they are all put together into a bigger solution, they will function without error. This unit framework allows us to use what is called the test-driven development approach.

Now let’s look at a simple example of a requirement in which we will use the unit test framework. Consider this simple code:
class my_class definition .
  public section.
    methods square importing int1         type i
                   returning value(sq_in) type i .
endclass.
class my_class implementation.
  method square.
    sq_in = int1 * int1.
  endmethod.
endclass.

Our code has a class called my_class and has a method called SQUARE . The purpose of the method is to square the number it imports and return the square as a parameter. The square method is called the production method, whereas my_class is referred to as the production class in the Unit Test Framework.

We will now code a class to act as a test class. We call this mytestclass. In order to code it, we need to add FOR TESTING to the method definition. Likewise, we add the keyword FOR TESTING to our CHECK_SQUARE method to designate it as a test method. These additions separate the class from the productive code.

We also add pseudo comments #AU Risk_Level and #AU Duration :
CLASS mytestclass DEFINITION FOR TESTING
  Risk Level Harmless
  Duration   Short
.
  PUBLIC SECTION.
    METHODS check_square FOR TESTING.
ENDCLASS.

Note

Before ABAP 7.02, pseudo comments allowed the framework to learn about the ABAP unit class. From 7.02 onward, we use addition RISK LEVEL and DURATION in the class definition.

Recall that the risk level can be critical, dangerous, or harmless and the duration can be short, medium, and long.

Now that we have our test class ready, let’s implement the test method. For testing the code, we need to:
  1. 1.

    Create an object of my_class.

     
  2. 2.

    Call the SQUARE method of this class. A value will be supplied to the method and the result will be calculated in the method and returned (if we supplied 10, we would expect a squared value of 100 to be returned).

     
  3. 3.

    Compare the actual value returned from the square method to our expected result.

    If these two match, no error is present.

    On the other hand, if actual and expected result do not match, we need to inform the ABAP Unit Framework of this erroneous state.

     
  4. 4.

    For this, we use methods of the standard class CL_AUNIT_ASSERT. In our example we will use the ASSERT_EQUALS method of this class.

     
All this is shown in the following code:
CLASS mytestclass IMPLEMENTATION.
  METHOD check_square .
    DATA:  obj TYPE REF TO my_class.
    DATA:  square TYPE i.
    CREATE OBJECT obj.
    square  = obj->square( 10 ).
    cl_aunit_assert=>assert_equals(
        EXP                  = 100
        act                  = square
        msg                  = 'Wrong Result'
           ).
  ENDMETHOD.
ENDCLASS.

As you can see, we called the square method . We then call the ASSERT_EQUALS method . This method has three parameters—expected (EXP), actual (AC), and message (MSG). We supply the expected value 100 to the method, the actual value of the square computed by the test method square, and the message to be displayed if the values do not match.

Note

It is not mandatory for a test method to have this pattern. We show this style for consistency and better understanding

The complete code for our requirements is as follows.
class my_class definition .
  public section.
    methods square importing int1         type i
                   returning value(sq_in) type i .
endclass.
class my_class implementation.
  method square.
    sq_in = int1 * int1.
  endmethod.
endclass.
CLASS mytestclass DEFINITION FOR TESTING
  Risk Level Harmless
  Duration   Short
.
  PUBLIC SECTION.
    METHODS check_square FOR TESTING.
ENDCLASS.
CLASS mytestclass IMPLEMENTATION.
  METHOD check_square .
    DATA:  obj TYPE REF TO my_class.
    DATA:  square TYPE i.
    CREATE OBJECT obj.
    square  = obj->square( 10 ).
    cl_aunit_assert=>assert_equals(
        EXP                  = 100
        act                  = square
        msg                  = 'Wrong Result'
           ).
  ENDMETHOD.
ENDCLASS.

Executing a Unit Test

Now that the code is complete, we will execute the unit test and check the results.

Before going into details, it is a good idea to look at the menu options within the ABAP transactions (class editor, program editor, and function module editor) that pertain to unit tests. Transactions SE37, SE80, and SE24 have separate menu options for executing unit tests:
  • For Class Builder, use Class ➤ Unit Test.

  • For programs using SE38, use Program ➤ Execute ➤ Unit Tests.

  • For the Function Module (transaction SE37), use Function Module ➤ Test ➤ Unit Test.

For our code example shown in the last section, we would use the relevant menu option Program ➤ Execute ➤ Unit Tests. In our case, the expected and actual results are the same, so no error messages appear. Only one message will be displayed on the status bar, as shown in Figure 7-2.
../images/478428_1_En_7_Chapter/478428_1_En_7_Fig2_HTML.jpg
Figure 7-2

Status message

You may also choose Execute ➤ Unit Tests With ➤ Coverage in order to view the details. This is shown in Figure 7-3.
../images/478428_1_En_7_Chapter/478428_1_En_7_Fig3_HTML.jpg
Figure 7-3

Unit test menu option

This will display results, as shown in Figure 7-4.
../images/478428_1_En_7_Chapter/478428_1_En_7_Fig4_HTML.jpg
Figure 7-4

Coverage

Now let’s complicate things a little. As you see in our code, we have correctly used the square function . I will now purposely create an error by using addition instead of multiplication:
class my_class implementation.
  method square.
    sq_in = int1 + int1. ""  wrong should be *  and not +
  endmethod.
endclass.
If we rerun the unit test result, we will now get messages denoting something went wrong. These error messages are shown in Figure 7-5.
../images/478428_1_En_7_Chapter/478428_1_En_7_Fig5_HTML.jpg
Figure 7-5

Unit result display

The task is shown in the form of a tree showing the program name, class name, and method name. We also see the test class and method in which the problem has occurred. Here, we are also shown the number of failed assertion(s).

On the right-bottom part of screen (see Figure 7-6), we can see the actual and expected values shown as 20 and 100, respectively. This clearly shows the developer that the production method implementation is not correct. We also can display the line number where the error occurred. By simply double-clicking the line number, we can go to the exact line within the source code.

We also see the actual error message. Note the text Wrong Result was specified by us via the ASSERT_EQUALS method call (see Figure 7-6).
../images/478428_1_En_7_Chapter/478428_1_En_7_Fig6_HTML.jpg
Figure 7-6

Failures and Messages window

As mentioned earlier, there is a mistake in the implementation of the production method. Instead of multiplication. we used addition. Once we correct the method and rerun the test, the results will not show any error messages.

Methods in CL_ABAP_UNIT_ASSERT for Testing

The CL_ABAP_UNIT_ASSERT class has several methods, known as assertion methods. They are used to pass messages to the ABAP Unit engine.

Before moving forward, it is a good idea to understand the main methods provided by the the CL_ABAP_UNIT_ASSERT class. These methods are shown in Figure 7-7.
../images/478428_1_En_7_Chapter/478428_1_En_7_Fig7_HTML.jpg
Figure 7-7

Class methods

Some of the more useful and commonly used methods are shown:
  • ASSERT_EQUALS

  • ASSERT_DIFFERS

  • ASSERT_BOUND

  • ASSERT_NOT_BOUND

  • ASSERT_INITIAL

  • ASSERT_NOT_INITIAL

  • ASSERT_CHAR_CP

  • ASSERT_CHAR_NP

  • ASSERT_EQUALS_F

  • FAIL

  • ABORT

Let’s look at the purpose of these methods:
  • ASSERT_EQUALS. Checks if two data objects are equal.

  • ASSERT_DIFFERS. Checks if two data objects are different.

  • ASSERT_BOUND. Checks if the reference variable is pointing to a valid reference.

  • ASSERT_NOT_BOUND. Checks for the invalidity (initial) of the reference of a reference variable.

  • ASSERT_NOT_INITIAL. Determines whether a data object is storing its initial value.

  • ASSERT_SUBRC. Determines whether the return code variable SY-SUBRC has a specific value.

Of special importance is the ASSERT_EQUALS method . It is the most commonly used method and is shown in Figure 7-8.
../images/478428_1_En_7_Chapter/478428_1_En_7_Fig8_HTML.jpg
Figure 7-8

Method parameters

As mentioned earlier, it checks the equality of two variables. The parameters of the method are as follows:
  • ACT. Actual result

  • EXP. Expected result

  • MSG. Message to be displayed

  • LEVEL. Error level (tolerable/critical/fatal)

  • Quit. Defines how the flow level is controlled when the test fails. Possible values of Quit include:
    • No (0). No action taken. The execution of the current test method continues.

    • Method (1). The test method is interrupted.

    • Class (2). The test class is interrupted.

    • Program (3). All test classes in the tested program are stopped.

  • Level. Has the following values:
    • Tolerable

    • Critical

    • Fatal

  • TOL. Tolerance

If the given tolerance is exceeded, an error is displayed. Let’s see this with an example. Suppose we have the following values:
  • Actual result: 99

  • Expected result: 100

  • Tolerance specified as 0.9999

  • Difference = Expected Result - Actual Result

In this case, the difference is 100 – 99 = 1. Since 1 is greater than the tolerance limit (.9999), this is above the tolerance limit. Hence, an error would be displayed.

There are certain private methods employed within test classes that are provided by the Unit Test Framework. They include the test as well as the links required for running the tests. These methods are:
  • SETUP( ). An instance method run prior to each test or execution of a test method.

  • TEARDOWN( ). An instance method run after execution of a test method.

  • CLASS_SETUP( ). A static method run once prior to all the tests of a given class. This is used for initializing variables that will be used in the tests.

  • CLASS_TEARDOWN( ). A static method that is run after all tests of the class have been run. This is used for clearing any data variables used.

These optional methods are also known as fixture methods . These names are predefined so they can be recognized at execution time.

ABAP Unit Results in Code Inspector

We also can see the ABAP unit test results using the Code Inspector. Within the variant, we need to check the ABAP unit test within the Dynamic Tests category. Let’s see how this is done.

First, we call transaction SCI. The screen shown in Figure 7-9 will appear.
../images/478428_1_En_7_Chapter/478428_1_En_7_Fig9_HTML.jpg
Figure 7-9

SCI transaction

Enter a suitable name for the check variant (in our case, it is Z_UNIT) and click the Create button under the field provided. The screen shown in Figure 7-10 appears.
../images/478428_1_En_7_Chapter/478428_1_En_7_Fig10_HTML.jpg
Figure 7-10

Check variant

Click the arrow icon for further settings (see Figure 7-11). Make sure to check the ABAP unit test as shown in Figure 7-11.
../images/478428_1_En_7_Chapter/478428_1_En_7_Fig11_HTML.jpg
Figure 7-11

ABAP unit parameters

Once this is done, we can use this variant in our code inspections.

We will now create a code inspection ZS_1 . For this code inspection, we assume that the object set ZS_2 already exists. The checks will be executed against that object set. We create an inspection using our variant Z_UNIT, as shown in Figure 7-12.
../images/478428_1_En_7_Chapter/478428_1_En_7_Fig12_HTML.jpg
Figure 7-12

Inspection ZS_1

When we view the inspection results, we can see that the ABAP unit related errors, warnings, and other messages. This is shown in the Code Inspector results (see Figure 7-13).
../images/478428_1_En_7_Chapter/478428_1_En_7_Fig13_HTML.jpg
Figure 7-13

Code Inspector results

As an example, we have executed this inspection on the program we earlier created in the chapter involving squares. Clicking the message will take us to the exact location where the error occurred.

Exceptions in ABAP Unit Tests

As with classes in general, exceptions may occur in unit test classes as well. If an exception occurs with a method, the unit test fails. The exception may be reported as the reason for the failure. If the method declares and includes the exception in the signature, the test exception may be propagated to the ABAP runtime.

A preferred approach is that the test method declares the exception in a signature in order to clarify the functioning of the method. However, the exception should be caught in the test method.
METHODS m_test_method FOR TESTING
  RAISING cx_sy_zerodivide.
...
METHOD m_test_method.
  obj->division( num = 10 ).
...
ENDMETHOD.
For provoked exceptions in the method under testing, the developer can include a call to the FAIL method (contained in the CL_ABAP_UNIT_ASSERT class) to report the failure of a given test. The code for this is shown here:
...
METHOD m_test_method.
* catching a provoked exception
TRY.
  obj->division( num = 10 ).
...
  CATCH cx_sy_zerodivide.
ENDTRY.
cl_abap_unit_assert=>fail(
  msg = 'exception not raised'
  level = if_aunit_constants=>critical ).
ENDMETHOD.

Enabling and Executing ABAP Unit Browser

SAP provides an ABAP unit browser for searching and viewing unit test classes residing within the system. The ABAP unit browser is embedded in transaction SE80. By default, the ABAP unit browser is switched off, and should be first switched on in order to be used.

In this section, we learn how to enable the unit test browser and how to run it in order to view the various unit classes defined in our system. Follow these steps:
  • Call transaction SE80. By default, the screen on the left side will appear, as shown in Figure 7-14.

    ../images/478428_1_En_7_Chapter/478428_1_En_7_Fig14_HTML.jpg
    Figure 7-14

    SE80 transaction

    As you will see, there is only a Repository Browser button on the top. We want to include a second button by the name Unit Browser over here.

  • Choose Utilities ➤ Settings. This will open the dialog box shown in Figure 7-15.
    ../images/478428_1_En_7_Chapter/478428_1_En_7_Fig15_HTML.jpg
    Figure 7-15

    User-specific settings

  • Click the Workbench (General) Settings. Then, in the browser selection, click the ABAP Unit Browser button and click the Continue button.

  • Next, you will see that the ABAP Unit Browser button will appear, as shown in SE80. It’s shown in the left pane in Figure 7-16.
    ../images/478428_1_En_7_Chapter/478428_1_En_7_Fig16_HTML.jpg
    Figure 7-16

    ABAP unit browser

  • Now click the ABAP Unit Browser button and choose Package in the first list box. Enter $tmp in the field provided (see Figure 7-17). We will then click the Display button. (As an example, we will browse through local objects, so we have used $tmp.) Then, click the Display button.
    ../images/478428_1_En_7_Chapter/478428_1_En_7_Fig17_HTML.jpg
    Figure 7-17

    ABAP unit browser

  • You will see that the various unit test classes appear, as shown in Figure 7-18. As a matter of example, we had earlier created a global test class by the name ZSt19_class.
    ../images/478428_1_En_7_Chapter/478428_1_En_7_Fig18_HTML.jpg
    Figure 7-18

    ABAP unit test classes

Double-clicking the unit class name in the left pane will show details of the class in the right pane.

Summary

In this chapter, we covered various types of testing. We learned what unit testing and test-driven development are and covered the advantages of unit testing. Finally, we saw a full-fledged programming demo. We also executed a unit test and checked the results with and without the Code Inspector. We ended the chapter with a note on the unit test browser, which is available for searching and displaying unit test classes residing in the ABAP system.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.163.229