Attention ABAP Developers! Boost The Quality of Your Programs by Writing Automated Unit Tests With ABAP Unit PDF

Download as pdf or txt
Download as pdf or txt
You are on page 1of 32

Attention ABAP Developers!

Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit
Jrgen Staader

How many ABAP developers can honestly say that testing is their favorite aspect of software development? Hmmm, it sounds pretty quiet out there. Implementing tests often feels like a tedious waste of time. After all, testing just proves the correctness of the code, right? And being good developers, dont we all code correctly anyway? On the other hand, we are well-educated developers, and as such we are fully aware of the utmost importance of thorough automated testing. Until now, ABAP developers had no viable way of resolving the conflict between the importance of testing during development and the available options for automating it. Starting with SAP Web Application Server (SAP Web AS) Release 6.40, a new tool called ABAP Unit enters the stage with the following benefits: ABAP Unit allows you to concentrate on the test coding, rather than how to run the tests or how to interpret and represent the results. Tests become an integrated development aid, rather than an extra task purely for meeting quality standards. Individual tests quickly accumulate to form comprehensive test suites that can be run automatically. Successful execution of test suites validates the quality of your software.

Jrgen Staader studied mechanical engineering at the University of Stuttgart, Germany. After working for five years at an engineering company, Jrgen joined SAP in 2000. Since then, he has been engaged in the design, development, and maintenance of various test tools for ABAP, C/C++, and Java, including ABAP Unit. Jrgen can be reached at [email protected].

For site licenses and volume subscriptions, call 1-781-751-8799.

SAP Professional Journal

January/February 2005

This article introduces you to the ABAP Unit test tool and shows you how to use it effectively, saving you valuable time and effort, while at the same time producing higher-quality code. First, well look at the principles and benefits of unit testing. Then, well look at ABAP Unit itself and how it works, including how to create, run, and interpret unit tests.

Continuous Unit Testing vs. Downstream Functional Testing


Traditionally, the testing phase for ABAP projects begins only after all the code is written. At first glance, this sequence seems logical; after all, how can we test something that does not yet exist?2 However, if you restrict testing to isolated units i.e., if you split your coding into small, independent portions you no longer need to wait until you complete the project to test it, in order to be sure that all code dependencies are covered. Instead, you can begin unit testing during the development phase itself. One problem with having a dedicated testing phase downstream from the implementation phase is that you find bugs comparatively late in the project. Until then, you and your fellow project team members work with buggy code and spend valuable time searching for and fixing inherent bugs instead of writing new code. The system becomes increasingly more complete and complex as the implementation phase progresses, thus the later a bug is found, the harder it is to identify, and the more expensive it becomes to correct. In contrast, unit testing helps you detect bugs early in the implementation phase. Another problem of downstream testing relates to project schedules that are typically fixed well in advance. If some unforeseen incident delays progress, you might be tempted to meet a deadline at the expense of shortening the testing phase, a tradeoff that would clearly affect project quality. In contrast, unit testing allows you to distribute tests throughout the implementation phase, which fosters confidence in your code at all times. This approach also reduces the risk of unpleasant surprises during final testing. While automated functional testing is wellcovered by the extended Computer Aided Test Tool
2

Principles and Benefits of Unit Testing


In order to understand the full value of ABAP Unit, lets start by considering the nature of a unit test. According to the Institute of Electrical and Electronics Engineers (IEEE), unit testing means testing of individual hardware or software units or groups of related units. 1 The meaningful unit for a unit test must be a nontrivial, accessible code fragment in which a given input or action causes a verifiable effect. In ABAP, a unit is typically a single method, a function module, or a form. Ideally, you should test such a unit in isolation from any other unit, so it does not depend on the execution of any other portion of the code. This definition offers the key to the benefits of unit testing. Since a good unit test doesnt rely on any dependent code, early testing is possible. Also, because the scope in which you search for an error is strictly limited, error detection is easier. And finally, addressing a nontrivial portion of the code avoids wasting time testing things that could not possibly break, such as a single-line accessor method in ABAP Objects. Next, well take a look at how the unit testing approach compares with the classic functional testing approach.
1

IEEE Standard Glossary of Software Engineering Terminology, Standard #610.12-1990.

Later in the article I will revisit this question, and show that it actually can make a lot of sense to write tests for something that does not yet exist.

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

(eCATT),3 there has been no tool support for automated unit testing in ABAP until now. This article shows you how the new ABAP Unit tool closes the unit testing gap. So what does all this mean in terms of who is responsible for implementing the tests? Well look at this next.

combination of these techniques, to test their code. The drawbacks of these techniques are evident. Debugging takes time and effort, and tracing quickly produces unmanageable amounts of information you need to analyze. Because it is difficult to anticipate which specific details are useful, you typically need to capture a vast amount of information in each trace, which has the effect of obscuring the vital information (i.e., causing scroll-blindness). Also, just because a piece of code works now doesnt guarantee that it will after the next few development iterations, so you need to constantly retest it a task that can become monumental as the code increases in size and complexity. Ideally, you do not want to be bothered with testing a piece of code after you have determined it is correct. You want automated, unattended, repeatable tests, but temporary test code, debugging, and tracing dont produce results that can be used for this purpose. What is a developer to do? Turn to the ABAP Unit test tool. This article shows you how to use ABAP Unit functionality to create repeatable test code that guarantees once-working functionality is never broken by a later modification (also known as regression testing), and in turn reduces the amount of hidden extra testing effort you need to expend during development. Although it requires some extra time and effort up front to write unit tests, it more than pays for itself down the road when you have fewer bugs, and need less time to fix them.

Unit Tests Are Developer Tests


While classic functional testing of a complete system is typically performed by dedicated quality engineers with specialized job profiles, unit tests are best created by the developers of the units to be tested. A closer look at the development process reveals that most developers already perform some type of testing during the implementation phase it is just perceived as part of the development effort rather than as an extra testing task. For example, suppose you want to check whether a newly written part of the code (e.g., a function) behaves as expected before you write the next piece of code. You would typically write a temporary test code fragment that provides some (more or less meaningful) test data to satisfy the functions signature, and then call the function. (Congratulations, by the way you just wrote a unit test!) Then, you set a breakpoint in the function entry and check whether the code behaves as intended. This initial effort is small compared to creating an automated, repeatable test. Nevertheless, if you need to test this piece of code again (at least once after each subsequent modification), you may soon wish you had spent a little extra effort up front to make this testing (and your life) a bit easier. As this example shows, classic developer tests consist of writing temporary test fragments and debugging. Many developers also use tracing, or a
3

Unit Tests Are Beneficial for Maintenance, Too


I have emphasized the advantages of being able to test early and often during development. However, the value of unit testing isnt restricted to the development phase of the software lifecycle unit tests are useful during the maintenance phase as well. If a bug only arises in production, write a unit test to identify and reproduce the bug. Then fix the

For more information, see the article Extend the Range and Reduce the Costs of Your SAP Testing Activities with eCATT in the January/February 2003 issue of SAP Professional Journal.

For site licenses and volume subscriptions, call 1-781-751-8799.

SAP Professional Journal

January/February 2005

bug and validate it using this unit test. Using unit tests for regression testing ensures that this bug never reappears. This article teaches you how to write such a test.

Four Steps to Creating a Unit Test


1. Consider what you want to test (that is, the unit to be tested), such as a function module or a specific method of a class. This tested code belongs to an ABAP program, and its unit test is part of the same program. 2. Add the unit test to the program. You write unit tests in ordinary ABAP using the editor for the program, such as the ABAP Editor (transaction SE38) for reports or the Class Builder (transaction SE24) for global classes. 3. Run the unit test from the ABAP Workbench via the menu command provided by the particular editor in use (Figure 11 later in the article summarizes these commands). 4. Analyze the results in case of failure. Keep in mind that a successful test simply raises a success message.

Unit Tests Are Easier Than You Think


The charm of ABAP Unit is that you need to learn very little in order to reap its benefits. You write the tests in the language with which you are already familiar (ABAP) and in the environment that you use all the time (the ABAP Workbench). This article teaches you everything you need to know to get started putting ABAP Unit to work for you.

The Basics What Is ABAP Unit?


Unit testing tools have existed for some time for most modern programming languages. ABAP Unit is the new tool that brings unit testing capabilities, and thus all their advantages, into the ABAP environment.4 As you will see, ABAP Unit additionally enhances the unit testing concept with its close integration into the ABAP language, and its support for mass testing as well as individual testing. From a developers perspective, ABAP Unit consists of: The ability to write a unit test in ABAP with designated test classes and test methods

Commands to run unit tests on programs from within the ABAP Workbench A result display for analyzing unit test errors Integration into and extension of the ABAP Code Inspector (transaction SCI) for running mass tests5

Unit testing tools for many languages are typically based on an underlying architecture called xUnit, a language-independent test framework that ties back to Kent Beck and originated in a test tool for SmallTalk (sometimes referred to as SUnit). This testing concept and its test framework architecture became very popular with the Java implementation JUnit, which was written by Erich Gamma and Kent Beck. ABAP Unit follows in this tradition.

You run the ABAP Unit tool for at least one program, for which ABAP Unit calls all the tests that were embedded into that program. You can add ABAP Unit tests to any of the following program types:

See the article Evaluating the Quality of Your ABAP Programs and Other Repository Objects with the Code Inspector (SAP Professional Journal, January/February 2003).

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

Executable programs Module pools Function groups Class pools6

Private vs. Public Section Declarations


Experienced ABAP Objects programmers may wonder why this example declares the test method in the private section. This declaration prevents external use of the test method; a declaration in the public section would allow external use. While not required, this type of declaration is typical because you rarely want to call test methods explicitly. Instead, you simply enter the appropriate command for ABAP Unit to run the test. The test driver has an implicit friend relationship to all tests, meaning that it can run any test regardless of its visibility (public, protected, or private). In rare cases, you might prefer a visibility other than private: If you choose protected, you typically intend to derive a test class from another test class, and also want to run the inherited test methods in the derived test class. If you choose public, you intend to use delegation, meaning that you want to use test code from one test class in another test class (for example, if you want to call a test method of one test class multiple times from a test method of another test class).

So, what does an actual ABAP Unit test look like when it is embedded within a program? Because you write ABAP Unit tests in ABAP (see the sidebar on the previous page), a procedure call looks exactly the same in both the regular production code and in the test code. There is no real difference from a code perspective. You dont need to learn a new language for testing and continually switch between production and test languages. You implement ABAP Unit test code in test methods inside test classes, which are then added to the code of the tested program. In order to express the test nature of these classes and methods, the ABAP language syntax was extended by the new FOR TESTING addition. A test class is simply a local class with FOR TESTING added to its definition. A test method is an instance method, without parameters, that is inside a test class that has FOR TESTING added to its definition. The following example shows some code for defining a test class (test_class) that has a single test method (test_method):
class test_class definition for testing. private section. methods: test_method for testing. endclass.

A class pool is the ABAP program frame for a global class. It is automatically generated when you create a new global class using the Class Builder (transaction SE24). A class pool serves as the container for exactly one global class, therefore, inside a class pool means the same as inside a global class.

Contrary to the test definition, where the FOR TESTING addition identifies the test nature of the classes and methods, the actual test implementation is no different from an ordinary production class implementation. The only thing you need from the testing context of ABAP Unit is a service class, which provides a number of static methods that allow you to positively verify your test assumptions. I discuss the methods of this service class in detail later in the article.

For site licenses and volume subscriptions, call 1-781-751-8799.

SAP Professional Journal

January/February 2005

Figure 1

ABAP Unit Test Hierarchy


Test Task The programs being tested (i.e., under test) are aggregated in a test task Program A Program B Test classes belong organizationally and physically to the program under test Test Class A Test Class B Test Class C Test Class D Test Class E Program C

The actual tests are implemented as test methods, which are grouped in the test classes Test Method Test Method Test Method Test Method Test Method Test Method Test Method Test Method Test Method

Figure 1 illustrates the ABAP Unit test hierarchy. A test task (which ABAP Unit automatically creates for you) defines the programs to be tested together in a single test run. When running ABAP Unit from within the ABAP Workbench, the test task consists of exactly one program the one that is currently open in the particular editor in use. Each program can have many test classes, each of which can contain many test methods.

and SAP documentation for demonstration and training purposes. All shipped SAP systems include its corresponding database tables. Using the Class Builder (transaction SE24), create a CL_AIR_CARRIERS global class as a simple wrapper for the SCARR database table. This class applies to air carriers and includes methods to add or delete a carrier, obtain the name and Web address for a specified carrier ID, and retrieve the number of all available carriers (see Figure 2).

Creating a Program Example to Unit Test


The aim of unit testing is to check and prove that the units e.g., the methods, function modules, or forms of a program work properly. The tested program is commonly referred to as the program under test. Before expanding the test example (the test_class definition in the previous section), we first need some imaginary production code we can test. For simplicity, the examples in this article use the well-known flight data model used in ABAP training

Following the Examples


When following these examples in the Customer namespace, you may need to insert Y_ , Z_ , or your company name as a prefix to the class name.

The examples in this article only use the ADD and GET_COUNT methods of the CL_AIR_CARRIERS class. To follow along, simply create a global class with these two methods only and specify the signature for them. The ADD method has one input parameter:

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

Figure 2

Example CL_AIR_CARRIERS Class Definition

importing AIRLINE type SCARR

The GET_COUNT method returns the following result:


returning value(RESULT) type I.

This will probably surprise you, but you can ignore the actual implementation of the production code for now all you need is the class definition in order to compile the unit tests. It doesnt even matter whether the method bodies contain any code at this point.

Consequently, you really dont need the actual implementation of a class in order to test it! Of course, the tests will fail without a corresponding implementation of the production code, but once you have created all the necessary tests, you can gradually implement your production code and continually test it along the way. With this approach, the further you proceed with the production code, the fewer failures your tests will produce. Quite simply, you are finished when all your tests succeed. This development strategy, which was first introduced by the Extreme Programming (XP) methodology, is known as the Test First principle (see the sidebar below).

The Role of Unit Testing in Lightweight Programming Methodologies


The modern lightweight programming methodology Extreme Programming (XP) has played a significant role in the broad acceptance of unit testing unit testing supports and enables collective code ownership and continuous software refinement, which are key elements of this programming practice. Kent Beck, initiator of XP and author of the book Extreme Programming Explained: Embrace Change, points out that none of the ideas in XP are new. Most are as old as programming. He sees the

(continued on next page)

For site licenses and volume subscriptions, call 1-781-751-8799.

SAP Professional Journal

January/February 2005

(continued from previous page)

innovation in combining commonsense principles and practices. XP assures their thorough exertion and mutual greatest possible support, and takes them to extreme levels hence the name. Even if you arent using XP (and that is OK with Kent Beck, if you correctly decide not to use XP), its great merit is still to show us quite plainly these very effective software practices and to remind us of their value. Some of them are just as valuable to the conventional software development process. In the context of unit testing, XP emphasizes test automation; the straightforward creation, management, and execution of tests; complete test coverage (except for trivial code like simple accessor methods); and always-faultless test results. If a once-faultless test execution is no longer successful after a modification, then you know for sure that the modification broke the code. XP also proposes that tests drive development, which means that you write the tests first and only then write the production code the Test First principle. Of course, writing the tests before the production code means they will fail, and in fact not even compile, as there is no corresponding implementation, but it allows you to clarify how the production code should look, and how you want to use it. Next, you provide the production code interfaces, so the tests compile, and then implement the production code itself. If the existing tests succeed, think of additional tests that could possibly break the code. You know you have finished the implementation when you cant identify any.

Now that we have something to test, lets create the corresponding unit test that well use to test it.

Language-Integrated Unit Testing


So now that were ready to create a unit test for our example class, where exactly do we create it? Traditionally, production and test code are separated into different compilation units such as physical files or programs, depending on the language. However, that separation is problematic because the production and test code are logically very tightly coupled. Presuming full test coverage, if you make any interface or semantic changes in the production code, you must also reflect the same changes in the test code in order to run the tests successfully. Unfortunately, the physical separation of the production and test code complicates this fundamental

prerequisite. Keeping the production and test code synchronized requires care and effort. Suppose someone changes the production code at some point in the future. Might that person overlook the separate test program associated with that code? (In an ideal world, appropriate test code exists for all production code!) When the tests eventually fail, is the unfortunate test author then responsible for tracking down the developer who made the incomplete modification? Ultimately, how can you ensure that both production and test code are transported together? This separation has an additional consequence that is particularly relevant for ABAP. It means that the tests have an external view into the production code, which can make it difficult to fully test the production code. Just think of what it takes to access and test a local class inside a program from another program. The left side of Figure 3 illustrates this situation and its potential problems. The depiction of these difficulties imply what you really need a common compilation unit for both

10

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

Figure 3

External vs. Internal Test Code


Traditional Approach: Production Code and Test Code in Separate Compilation Units
Limitation: External view with limited access to the implementation.
Production Code Test Code

New Approach: Production Code and Test Code in a Common Compilation Unit
Internal view with unlimited access to the implementation.
Production Code Test Code

Problem: Version synchronization. Is there a matching test version for the production code version? Which is the matching test version?
Production Code Version X Test Code Version X

Version synchronization is not a problem. The test code is embedded within the production code.
Production Code Version X Production Code Version Z

Production Code Version Y

Test Code Version X Test Code Version Z

Test Code Version Z

Production Code Version Z

Problem: Transport synchronization. Will the matching versions of the test and production code arrive together at their destinations?
Production Code Test Code

No transport synchronization is necessary. The test code always comes along with the production code.
Production Code Test Code

Production Code Transport

Test Code Transport

Common Code Transport

production and test code. All the noted problems vanish with this approach, as you can see on the right side of Figure 3. The internal view of the test code allows the direct use of local classes inside programs such as class pools, because the test classes are in the same program. Synchronization problems are solved and the tests that correspond to the code are clear since they are embedded in the code to be tested. Transport no longer requires synchronization because you have a single, inseparable transport object. So why hasnt this approach been taken before?

One problem is the potential for increased system load. When tests are embedded in production code, both entities must always be loaded together when needed. If you take unit testing seriously, the amount of test code could easily exceed the amount of production code, so this approach would double the program load, resulting in serious performance degradation caused by code that isnt even relevant to production! Another drawback is maintaining data integrity and security. Because the tests themselves are written in ABAP, they could potentially do things that are

For site licenses and volume subscriptions, call 1-781-751-8799.

11

SAP Professional Journal

January/February 2005

Figure 4

Program Load Without Test Code

Figure 5

No Access to Test Code

Production Code Test Code

Production Code Test Code

No access from production code to test code Full access from test code to production code

unacceptable in a production system for example, test operations might need to access the database or even manipulate or delete database content. For these performance and security reasons, tests should never be executed in a production environment. So how do we get the benefits of this approach without the risks? The remedy is a new technique that SAP calls language-integrated unit testing. In a production environment, the tests are not part of the program load (see Figure 4). The tests are simply not present. The ABAP compiler distinguishes test code from regular production code, and generates the appropriate program load with or without the tests accordingly. In a production environment, the program load excludes local test classes marked as FOR TESTING. The primary consequence of excluding test code from production systems is that production code never references any test code. Aside from the fact that using or referencing test code in production code simply isnt meaningful, just imagine what would happen if the production code were allowed to reference the test code. The approach would work fine on a development system where the tests are part of the program load. But once the program was moved to the production environment, where the referenced test code is no longer available, the program would suddenly crash where it hurts the most during production use.

But dont worry! All measures have been taken in ABAP to make this consideration purely hypothetical. Static integrity is guaranteed by a syntax check that raises an error if you try to statically reference test code in your production code. Dynamic integrity is ensured by runtime checks. Any dynamic call from production code to test code causes a runtime error. In contrast, the test code always has full access to the production code (see Figure 5). Now you can place the test code in the same compilation unit as the production code. That means again speaking in ABAP terms to: Put test classes for reports in the report. Include dedicated test includes in function groups. Put test classes in the local implementation of class pools (choose Goto Class-local types Local class implementations in the Class Builder).7

Our example global class CL_AIR_CARRIERS is the class under test in this article. The program frame of a global class is a class pool, thus its test classes reside in its local implementation part.
7

You can put isolated, independent test classes in their entirety (that is, both the class definition and implementation) in the local class implementations section via this menu path. Alternatively, you can put the test class definition in the local class definitions section via the menu path Goto Class-local types Local class definitions/types. If your test classes have dependencies (that is, if you are using test inheritance or delegation), always put the test class definitions in the local class definitions section.

12

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

Figure 6

The Test Implementation

class test_air_carriers implementation. method add_carrier. data: SAPproAir type scarr, l_act type i. *

" an air carrier we can add " the actual number of airlines

create an instance of the class under test create object cut. prepare some test data: SAPproAir-carrid = 'S1'. SAPproAir-carrname = 'SAPpro Air'. SAPproAir-url = 'http://www.SAPpro.com'. call the method under test: cut->add( SAPproAir ). endmethod.

endclass.

Now were ready to create a unit test for the class we created back in Figure 2. Lets start by testing the ADD method, beginning with the test definition. Open the local implementation of the class under test (in this case, CL_AIR_CARRIERS), and enter the following test definition:
class test_air_carriers definition for testing. private section. methods: add_carrier for testing. data: cut type ref to cl_air_carriers. endclass.

contains additional test data designed to avoid redundancy when you add more test methods. This code fragment defines a reference (CUT) to the class under test simply for accessing this instance. Defining this reference once as a member of this class is more efficient than defining it separately in every test method. Next, supply the corresponding test implementation and fill it with some test code, as shown in Figure 6.8 The test example is now complete and executable, and calls the functionality to be examined. As you can see, the implementation part doesnt contain any testspecific syntax. It could just as well be production
8

Compared to the first test example (the earlier test_class definition), notice that this example

Note that SAP Professional Journal has not invested in air carriers for closer contact with its international SAP community. This example uses a fictitious air carrier to avert suspicion of surreptitious advertising.

For site licenses and volume subscriptions, call 1-781-751-8799.

13

SAP Professional Journal

January/February 2005

code. Nevertheless, you wouldnt notice whether the ADD method executed correctly because you have no way to verify the results of the method call. What you need now is a way to express and verify the expected test results. ABAP Unit provides assertion methods as part of its CL_AUNIT_ASSERT service class for this purpose, which we will look at in detail next.

Verifying Test Assertions


The CL_AUNIT_ASSERT service class provides several static assertion methods that you can use to verify your test results. In case of failure, this class launches an error that appears in the ABAP Unit result display as an assertion error (see the sidebar on page 25). Figure 7 lists the assertion methods along with their required and optional9 parameters. In order to choose the appropriate method, you need to understand what each of them do. Lets take a closer look at each in turn.

or FATAL, as defined in the IF_AUNIT_CONSTANTS interface and aliased in the CL_AUNIT_ASSERT class. This parameter has the AUNIT_LEVEL dictionary type, and its default value is CRITICAL. The ABAP Unit result display reflects this prioritization, which is particularly helpful during mass testing for judging the significance of a unit test error and prioritizing follow-up efforts. FATAL unit test errors should obviously cause more alarm than TOLERABLE errors. Regardless, your goal should always be faultless unit test results, and correcting unit test errors should receive top priority! QUIT affects the control flow of the test execution with a value of NO, METHOD, CLASS, or PROGRAM. This parameter has the AUNIT_FLOWCTRL dictionary type, and its default value is METHOD. The possible values for this parameter are defined in the IF_AUNIT_CONSTANTS interface and aliased in the CL_AUNIT_ASSERT class: NO means do not interrupt the test when an error occurs and continue the test with the statement that follows the failed assertion. METHOD means stop executing the test method when an error occurs. Remember that the purpose of the test is to prove the correctness of the tested production code. When that is not the case, you want to stop the test immediately and return from the method. CLASS means abort the test class execution and continue the test with the next test class. PROGRAM means the error is so serious that continuing to test the program further makes no sense. For example, you might use this value if a necessary precondition is not met (such as a missing resource), without which a program cannot operate.

Understanding the Assertion Method Parameters


Lets start by reviewing the common parameters of all assertion methods. They all support the following optional parameters: MSG is a message of type CSEQUENCE that identifies the cause of the failure. Its default value is the name of the called assertion method. Although this parameter is not required, it is good programming practice to always pass a message to this parameter. This technique expresses your intention for the test, providing valuable test documentation and potential error explanation. LEVEL is the priority of the assertion error, and has a value of TOLERABLE, CRITICAL,
Note that optional applies to the ABAP signature extension, as well as whether a default value is specified in the signature.

Some assertion methods also support one or more of the following parameters:

14

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

Figure 7
Method ASSERT_BOUND Purpose

ABAP Assertion Methods


Required Parameters ACT type ANY Optional Parameters and Parameters with Default Values MSG type CSEQUENCE LEVEL type AUNIT_LEVEL* QUIT type AUNIT_FLOWCTRL** MSG type CSEQUENCE LEVEL type AUNIT_LEVEL* TOL type F QUIT type AUNIT_FLOWCTRL** MSG type CSEQUENCE LEVEL type AUNIT_LEVEL* TOL type F QUIT type AUNIT_FLOWCTRL** MSG type CSEQUENCE LEVEL type AUNIT_LEVEL* QUIT type AUNIT_FLOWCTRL** MSG type CSEQUENCE LEVEL type AUNIT_LEVEL* QUIT type AUNIT_FLOWCTRL** MSG type CSEQUENCE LEVEL type AUNIT_LEVEL* QUIT type AUNIT_FLOWCTRL** MSG type CSEQUENCE LEVEL type AUNIT_LEVEL* QUIT type AUNIT_FLOWCTRL** MSG type CSEQUENCE LEVEL type AUNIT_LEVEL* QUIT type AUNIT_FLOWCTRL** DETAIL type CSEQUENCE

Ensure the validity of the reference for a reference variable Ensure the difference between two simple data objects (since SAP Web AS SP4 only) Ensure the equality of two data objects

ASSERT_DIFFERS

ACT type SIMPLE EXP type SIMPLE

ASSERT_EQUALS

ACT type ANY EXP type ANY

ASSERT_INITIAL

Ensure that an object has its initial value

ACT type ANY

ASSERT_NOT_BOUND

Ensure the invalidity of the reference for a reference variable Ensure that an object does not have its initial value Expect a distinct value for the return code SY-SUBRC (since SAP Web AS SP4 only) Terminate the test with an error

ACT type ANY

ASSERT_NOT_ INITIAL

ACT type ANY

ASSERT_SUBRC

ACT type SYSUBRC EXP type SYSUBRC

FAIL

None

* If you do not explicitly choose a value for the LEVEL parameter, the value will default to CRITICAL. ** If you do not explicitly choose a value for the QUIT parameter, the value will default to METHOD.

ACT is the actual value of the assertion verification, and is required by all of the assertion methods except for FAIL. Pass the actual value or reference that you want to check. The type is usually ANY, except for ASSERT_DIFFERS (type SIMPLE) and ASSERT_SUBRC (type SYSUBRC).

EXP is the corresponding expected value for assertions that compare the expected value with the actual value. It is required by the assertion methods ASSERT_EQUALS (type ANY) and ASSERT_DIFFERS (type SIMPLE), and is optional for the assertion method ASSERT_SUBRC (type SYSUBRC).

For site licenses and volume subscriptions, call 1-781-751-8799.

15

SAP Professional Journal

January/February 2005

Exception Handling in Test Methods


Dont bother handling any unexpected class-based exceptions thrown by tested code. You dont need to enclose the test code in a try ... catch block in order to catch exceptions that are raised in your tested production code, or construct an appropriate failure message. Simply leave the exception handling to ABAP Unit, which is well-equipped for this task. Class-based exceptions appear in the ABAP Unit result display as exception errors (see the sidebar on page 25 for more on the various ABAP Unit error types). The error message shows the exception type, and the detail section contains the exception text and the source location where the exception was raised. If the tested code raises an exception derived from the CX_STATIC_CHECK class,* the syntax check statically checks whether all exceptions that are raised or passed from a called procedure are either handled by a CATCH clause or explicitly declared in the calling methods interface. In this case, you must also declare the RAISING of this exception in the test method in order to propagate the exception to

* For more information about CX_STATIC_CHECK exceptions and class-based exception handling, see the article A Programmers Guide to the New Exception-Handling Concept in ABAP in the September/October 2002 issue of SAP Professional Journal.

TOL is the tolerance (of type f). This optional parameter applies only to comparisons of floatingpoint numbers (via the assertion methods ASSERT_DIFFERS and ASSERT_EQUALS). DETAIL is an additional detail message (of type CSEQUENCE) that further describes the error. This optional parameter applies only to the FAIL method, which doesnt provide any automatic error analysis.

Now that you understand the assertion method parameters, lets examine how and when to use each of the assertion methods.

Calling FAIL unconditionally causes an assertion error. This behavior is different from that of the assertion methods with the prefix ASSERT_, which verify the specified assertion and indicate an error only if the assertion is false. The error notification includes an analysis of the error with a detailed message that describes what is wrong with the assertion. The FAIL method doesnt check anything; it merely signals that an error occurred. Although the FAIL method doesnt automatically provide any additional information about the error, it supports parameters for this purpose. To provide additional information about the error, call this method with the MSG parameter (to provide a description of the error) and the DETAIL parameter (to further explain the error situation). In the ABAP Unit result display, the DETAIL message appears in the detail section for the error. While you can use the FAIL method when you cant adequately express an assertion with the specialized assert methods, it is unlikely that you will

Using the General-Purpose FAIL Assertion Method


FAIL is the simplest and most general assertion method. It supports the common parameters MSG, LEVEL, and QUIT, and the optional parameter DETAIL.

16

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

ABAP Unit. As shown in the following example, use the CX_STATIC_CHECK abstract superclass to declare that ABAP Unit handles all of its derived exceptions:
METHODS tip_exception_static_check FOR TESTING RAISING CX_STATIC_CHECK.

The only situation in which you would include a try catch block in your test code is when you want to verify the actual raising of the exception, as shown in the following example, where the call of a procedure correct_if_exception_raised is expected to raise an exception of the imaginary type CX_EXPECTED_EXCEPTION_TYPE:
method tip_exception_wanted. try. correct_if_exception_raised( ). cl_aunit_assert=>fail( msg = 'exception was not raised!' ). catch CX_EXPECTED_EXCEPTION_TYPE.

" if we get here, everything's fine. endtry. endmethod.

encounter such a scenario. FAIL is commonly used to verify the flow control of test code. Insert the FAIL method in control blocks that should not be passed through, such as within an if else block:
IF logical_expression. " test something else. cl_aunit_assert=>fail( ). endif.

In case of an error (that is, if the assertion turns out false), the error is reported. Unlike the FAIL method, these methods automatically generate detailed information about the error situation based on the specific assertion without the need for additional parameters. All of these assertion methods have the mandatory ACT parameter that provides the actual value to be examined. This parameter generally has the type ANY, allowing you to pass data of any type;10 two methods (ASSERT_DIFFERS and ASSERT_SUBRC) require ACT to have a more restricted type (SIMPLE and SYSUBRC, respectively).

Testing for exceptions also demonstrates a good example of using the FAIL method (see the sidebar above). In practice, this technique is perhaps the most important use of the FAIL method.

Using ASSERT_EQUALS for Comparing Expected and Actual Results

Using the Specialized ASSERT_ Assertion Methods


The assertion methods that are specialized for a particular purpose all start with the prefix ASSERT_. Each method expresses a specific assertion to be verified using built-in error analysis.

Lets start with the most important, most useful assertion method, ASSERT_EQUALS. Its usefulness stems from the fact that in a test you usually want to compare
10

ANY is the predefined generic ABAP type that can hold any arbitrary ABAP data type.

For site licenses and volume subscriptions, call 1-781-751-8799.

17

SAP Professional Journal

January/February 2005

the actual state or result with the expected state or result. Thus, in addition to the ACT parameter for the actual value, this method has a mandatory EXP parameter that provides the expected value. The following example illustrates how to use this method:
method test_fortune_teller. data: fortune_teller type ref to cl_fortune_teller, year type n length 4. create object fortune_teller. year = fortune_teller->the_year_ you_learned_ABAP_UNIT( ). cl_aunit_assert=>assert_equals( act = year exp = '2005' msg = 'fortune teller failed ' & 'on my ABAP knowledge' ). endmethod.

values with ABAP Unit where a direct comparison using the ABAP EQUALS operator would fail with a runtime error. For example, you could set up a standard table as the expected value and compare it with actual sorted and/or hashed tables. If values appear to be unequal, the detail section of the ABAP Unit result display shows where the values differ. For long character sequences, the wildcard symbol an asterisk (*) replaces matching sequences. For instance, suppose you want to compare the following strings:
This string is not very long but just an example

and
This string is not so long but just an example

In this example, you examine an imaginary CL_FORTUNE_TELLER class to check the quality of its forecasts in relation to ABAP Unit. Create a FORTUNE_TELLER instance of this class and ask it in what year you learned how to use ABAP Unit. Hopefully youll receive the right answer! If the values are not equal, an assertion error is launched. The detail section of the ABAP Unit result display shows where and why the two values differed. While that information may not sound exciting for simple types (such as in the fortune teller example), it becomes very interesting indeed for long character sequences, structured types, or tables. Have you ever tried to compare the contents of two large tables using the ABAP Debugger to find the difference between them? If so, you can greatly appreciate the fact that ABAP Unit can tell you precisely that line 789 differs, saving you from comparing the previous 788 lines yourself. Remember that complex types are all valid arguments for the ASSERT_EQUALS method because both values have the ANY generic data type. Before comparing the values, the method first ensures their comparability. Comparability is weaker in this context than for a direct comparison via the EQUALS operator in ABAP. In other words, you can compare

The analysis that appears in the result display would provide the following explanation:
Character String Different as of Position 19 Expected [*very*] Actual [*so*]

While seemingly insignificant in such a simple case, this aspect of the error analysis is really helpful for working with huge strings that you cant easily compare at a glance. The error analysis is even more beneficial for comparing huge or nested tables with structured table lines. The result display tells you exactly what is different if a single line is deleted, if lines are in a different order, or if an individual structure component differs. Figure 8 shows a sample error analysis in a partial screenshot of the ABAP Unit result display. (I explain how to interpret this screen in more detail later in the article.) This figure shows only the detail analysis section, which appears in tree format. In the left column, you expand and collapse the tree branches to display different granularities of the error analysis. The right column contains the explanation. Figure 8 shows the comparison of two internal tables that could be in the internal data format of our test example, which is a table of type SCARR.

18

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

Figure 8

ABAP Unit Detail Analysis for a Table Comparison

Size and type of internal table Missing line in expected table

Analysis down to component of table line Same item at different indices

The first two lines that appear after the heading Different Values show the size and the type of the internal table: Expected [S-Table[19x572] of \TYPE=SCARR] The result display also shows lines in one table that dont exist in the other: Table Value Index [3] of Actual Table Not in Expected Table Expanding the tree branches further provides more details, if available. It shows the differences down to the level of the relevant component if one table line differs: Different Table Values: Component [MANDT] Different Expected [000] Actual [ ]

You also see that the same item exists in both tables but at different table indices: Same Value at Different Table Indexes: Expected [2], Actual [6] Note that object references are compared for identity only and not for content equality. In other words, two object references are considered equal only if they reference the very same object. Two distinct objects with exactly the same contents evaluate to being different. The ASSERT_EQUALS method has one more optional parameter for tolerance, TOL. You only use this parameter for comparisons of floating-point numbers (of type f). Floating-point numbers cant be represented exactly, as it is impossible to represent an infinite amount of real numbers in a finite number of bits (or more precisely, in the finite number of 64 bits reserved by ABAP for floating-point

For site licenses and volume subscriptions, call 1-781-751-8799.

19

SAP Professional Journal

January/February 2005

Figure 9

Using the ASSERT_DIFFERS Method

method test_fortune_teller_repetition. data: year_ABAP_UNIT type n length 4, year_programming type n length 4. year_ABAP_UNIT = fortune_teller->the_year_you_learned_ABAP_UNIT( ). year_programming = fortune_teller->the_year_you_learned_coding( ). cl_aunit_assert=>assert_differs( act = year_ABAP_UNIT exp = year_programming msg = 'fortune teller is repeating its standard answer' ). endmethod.

numbers).11 This discrepancy becomes more apparent because the internal representation is base 2, instead of the more familiar base 10 representation. In short, an exact comparison of floating-point values seldom behaves as expected. Therefore, you specify a tolerance for expressing the range in which you consider two numbers to be equal. This tolerance is the maximum absolute difference between the two numbers for which the ASSERT_EQUALS should conclude that the values are equal and the check passes.

The ASSERT_DIFFERS method is the opposite of the ASSERT_EQUALS method, with the limitation that you can only use it with simple ABAP data types. The simple generic data type includes the elementary data types, as well as structured types with exclusively character-type flat components. ASSERT_DIFFERS has essentially the same parameter list and semantics as ASSERT_EQUALS, except for the EXP parameter (which in this context really means not expected). Continuing the fortune teller example from the ASSERT_EQUALS discussion, the example in Figure 9 uses the ASSERT_DIFFERS method to check whether the fortune teller has a standard answer to any question asking for a certain year. (For simplicity, I excluded the declaration and creation sections.) Unless you are not completely new to programming, this assertion should evaluate to true. The ASSERT_DIFFERS method is one of the two exceptions where the ACT parameter doesnt have the generic ABAP type ANY instead, ACT and EXP have the type SIMPLE. This limitation is due to the plausibility of such an assertion rather than a technical constraint. It is certainly helpful to be able to verify whether two timestamps or two unique identifiers are different. Nevertheless, sensing that one component of a complex data structure has changed is simply too imprecise. A noted difference could have many

Using the Other ASSERT_ Methods Effectively ABAP Unit provides several additional ASSERT_ methods for other specific purposes:
11

ASSERT_DIFFERS ASSERT_BOUND and ASSERT_NOT_BOUND ASSERT_INITIAL and ASSERT_NOT_INITIAL ASSERT_SUBRC


Floating-point numbers are displayed internally with 16 decimal places according to the IEEE-754 standard (double precision). For more information about floating-point arithmetic, refer to the book The Art of Computer Programming by Donald E. Knuth, or the paper What Every Computer Scientist Should Know About Floating-Point Arithmetic by David Goldberg (available at citeseer.ist.psu.edu/goldberg91what.html).

20

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

reasons. With simple data types, you can precisely specify what you expect to be different. The ASSERT_BOUND method verifies that a reference variable contains a valid reference. It has the common parameters ACT, MSG, QUIT, and LEVEL. This method behaves like the ABAP logical expression IS BOUND. It supports any type for the actual value (the ACT parameter). However, the assertion only passes if you pass data or an object typed with REF TO. Otherwise, an error is launched. The ASSERT_NOT_BOUND method (which is the opposite of the ASSERT_BOUND method) verifies that a reference variable does not contain a valid reference. It has the common parameters ACT, MSG, QUIT, and LEVEL. This method behaves like the ABAP logical expression IS NOT BOUND. For the actual value (the ACT parameter), you must pass data or an object typed with REF TO. Otherwise, an error is launched. The ASSERT_INITIAL method verifies that the actual value is initial i.e., that it contains its typespecific initial value. It has the common parameters ACT, MSG, QUIT, and LEVEL. This method behaves like the ABAP logical expression IS INITIAL. The ASSERT_NOT_INITIAL method (which is the opposite of the ASSERT_INITIAL method) verifies that the actual value is not initial in other words, that it contains a different value than its typespecific initial value. It has the common parameters ACT, MSG, QUIT, and LEVEL. This method behaves like the ABAP logical expression IS NOT INITIAL. Starting with SAP Web AS SP4, the new ASSERT_SUBRC method allows you to verify the state of the SY-SUBRC system field.12 After calling a statement that sets SY-SUBRC, it is sensible programming practice to check its content before continuing the process. However, you cant easily
12

perform this check with the ASSERT_EQUALS method. You would need to copy SY-SUBRC first, because simply calling ASSERT_EQUALS would reset SY-SUBRC to zero. This extra call is unnecessary with ASSERT_SUBRC, because with this method you pass the ACT parameter by value.13 Both the ACT and EXP parameters have the specific dictionary type SYSUBRC. (This method is the other exception for which the ACT and EXP parameters dont have the generic type ANY.) In general, an ABAP return value of zero means that the statement was executed without problems. In most cases, you dont need to explicitly specify the expected value (the EXP parameter), since its default value of zero is usually appropriate. You could simply use the following statement:
cl_aunit_assert=>assert_subrc( act = sy-subrc ).

You might choose to pass an explicit expected value via the EXP parameter if you want to explicitly test a failure situation in which you expect SY-SUBRC to have a value other than zero. Checking the value of SY-SUBRC is not the only benefit of this method. Often, non-class-based exceptions are used with ABAP messages (using the MESSAGE RAISING statement). Based on current practices, you typically raise a message if a nonclass-based exception is not handled by the caller. If ASSERT_SUBRC fails because of a return value that is different from what was expected, the ABAP Unit result display shows a possible corresponding message in the detail view for the error.

Choosing an Assertion Method for the Example Unit Test


Armed with an understanding of the assertion
13

SY-SUBRC is an important system field that contains the return code set by many ABAP statements. It is set to zero if the statement was successfully executed. Any other value signals a problem. Different values of SY-SUBRC are associated with different errors. See the ABAP online documentation for further details.

In the other assertion methods, all actual and expected values are passed by reference (rather than by value) due to the generic nature of these values. Since anticipating the type of object to be passed is impossible, general copying could introduce performance problems when passing huge tables or structures as parameters to the assertion methods.

For site licenses and volume subscriptions, call 1-781-751-8799.

21

SAP Professional Journal

January/February 2005

Figure 10
method add_carrier.

The Complete Test Implementation

data: SAPproAir type scarr, l_act type i. * *

" an air carrier we can add " the actual number of airlines

create an instance of the class under test create object cut. assert initial state l_act = cut->get_count( ). cl_aunit_assert=>assert_equals( act = l_act exp = 0 msg = 'before adding one airline' ). prepare the test data:

methods, you can now complete the test example by adding statements to verify the test assertion. The first step is to choose the appropriate method from the CL_AUNIT_ASSERT service class for this example, ASSERT_EQUALS. After calling the ADD method in the ADD_CARRIER test method in the example test implementation (Figure 6), you want to obtain the actual value and compare it to the expected value. In this example, you want to check how many airlines exist after adding one, which should be one. Insert the following code at the end of the test method:
* after adding one airline l_act = cut->get_count( ). cl_aunit_assert=>assert_equals( act = l_act exp = 1 msg = 'after adding one ' & 'airline' ).

Figure 10 shows the now-complete test example. It creates an instance of the class under test and asserts its initial state by checking that the air carrier counter is really set to 0 (that is, it doesnt yet contain any carriers). You provide an air carrier with valid data and add it to the list, which is the method tested in the example. Finally, the counter is checked again to verify that it now contains exactly one air carrier. The test for the ADD method presumes that the GET_COUNT method works correctly, as the assertion will fail if that method yields an incorrect value. GET_COUNT is most likely a trivial getter method that could not possibly break. Otherwise, you would also need to explicitly check its correct operation in a dedicated test method, so that you can rely on its results to confirm other test expectations.

Running the Unit Test


Real developer tests (as opposed to tests that are typically run by dedicated quality assurance testers) should be both written and executed within the development environment. A shift in the working environment also means a mental shift, which inherently creates more effort for the developer and results in a loss of efficiency. Experience also shows that developers are

If you are a distrustful person and you absolutely should be when writing unit tests! you also want to ensure that the newly created object didnt contain any airlines before you added one. In other words, you should check that the GET_COUNT method really returned 0 before adding the airline.

22

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

Figure 10 (continued)
SAPproAir-carrid SAPproAir-carrname SAPproAir-currcode SAPproAir-url * = = = = 'S1'. 'SAPpro Air'. 'USD'. 'http://www.SAPpro.com'.

call the method under test: cut->add( SAPproAir ). after adding one airline l_act = cut->get_count( ). cl_aunit_assert=>assert_equals( act = l_act exp = 1 msg = 'after adding one airline' ). endmethod.

more willing to write tests if they stay in their familiar development environment. ABAP Unit embraces this principle. You run unit tests for the program that is currently open in the ABAP Workbench with the Unit Test menu command,

which is available from several different development perspectives. In the Object Navigator (transaction SE80), you run unit tests with the Unit Test command on the context menu for the program (or part of it). Figure 11 describes where to find the Unit Test command in different ABAP Workbench screens.

Figure 11
Tool (Transaction) ABAP Editor (SE38) View

How to Run ABAP Unit Tests


Menu Path Program Execute Unit Test Program Test Unit Test Function Module Test Unit Test Function Module Test Unit Test Object type Unit Test Class Unit Test Method Unit Test Public/Prot./Priv. section Unit Test Local types Unit Test Loc. class implem. Unit Test Macros Unit Test Unit Test Execute Unit Test Test Unit Test Initial Screen Display

Function Builder (SE37)

Initial Screen Display

Class Builder (SE24)

Initial Screen Class Definition Method Def. Public/Prot./Priv. Section Class-local types

Object Navigator (SE80)

Context menu on various program types and parts of it

For site licenses and volume subscriptions, call 1-781-751-8799.

23

SAP Professional Journal

January/February 2005

Figure 12

Successful Test Message in Status Bar

If the tests run successfully, a success message appears in the status bar, as shown in Figure 12. If the program under test doesnt contain any tests, the following message appears instead: The active version of the class <CL_AIR_CARRIERS> contains no unit tests If you see this message, check whether you saved and activated the program under test. You can only execute ABAP Unit tests after activating a program, as you would for any ABAP program that you want to compile and mark as executable in the system.

with all its contained test classes and their contained test methods. This test hierarchy for a test run is created automatically when you run ABAP Unit for a specific program. You expand or collapse the tree branches in order to view summary results only, or the results down to the granularity of each individual test method. Lets take a closer look at how to interpret the test hierarchy. At the top of this tree display pane, you see the test task, which is the test run by ABAP Unit. ABAP Unit automatically creates the test task for you. Its name contains the user name, the execution date and time, and the system ID. When you run a test from the ABAP Workbench, the test task comprises exactly one program under test that is, the one that is currently open in the development tool (CL_AIR_CARRIERS in the example). Nested below that program, you see its active test classes and test methods. The icon next to each item allows you to quickly assess the aggregated state of the test for each: A green circle means that the test was error-free. A yellow triangle means that the test only produced TOLERABLE errors. A red square means that the test produced at least one CRITICAL or FATAL error.

Interpreting Unit Test Results in the ABAP Unit Result Display


The ABAP Unit result display appears automatically if an ABAP Unit test run from within the ABAP Workbench detects an error. This result display consists of three parts, as shown in Figure 13. ABAP Workbench test runs are considered to be personal test runs for development purposes and are not saved for future reference. You must use the ABAP Code Inspector (transaction SCI) in order to run and save the results of ABAP Unit tests (more on this in the next section). On the left side, you see an overview of the test results in a tree format that reflects the test hierarchy defined back in Figure 1. The test run in Figure 13 checked our example program CL_AIR_CARRIERS

On the right side of this tree display pane, you see the total number of errors sorted by level or type. Use the toggle button at the top of the tree display to switch between the display variants. The error level or priority shows the value that the test author specified for the LEVEL parameter (FATAL, CRITICAL,

24

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

Figure 13

ABAP Unit Result View

Error Messages

Test Result Overview

Message Details

or TOLERABLE), as described earlier in the section on the ABAP Unit assertion methods. Remember that the default value is CRITICAL for the LEVEL parameter

if it is not stated explicitly. The error type is one of the four types described in the sidebar below (assertion error, exception error, runtime error, or warning).

Understanding the ABAP Unit Error Types


ABAP Unit supports four types of errors: Assertion error: An assertion error is the most important error type because it is what you are explicitly testing. In other words, an assertion error occurs if your test assertion is not true. In a way, these errors are anticipated errors since you typically test what might go wrong. In the example test method (Figure 10), the second ASSERT_EQUALS verification checks if the ADD method doesnt execute properly and fails to add the airline. Of course, checking the counter is a rather weak test for the successful addition of air carrier data. A more complete assertion would also verify correct storage of the other information, such as the name and the currency. Exception error: Exception errors are more commonly unanticipated errors. Perhaps creating the instance does some complex things that could fail and raise an exception, such as retrieving data
(continued on next page)

For site licenses and volume subscriptions, call 1-781-751-8799.

25

SAP Professional Journal

January/February 2005

(continued from previous page)

from external resources or computing an initial state. You might not even be aware of this situation if the exception is derived from the base exception CX_NO_CHECK. Regardless, you never need to catch any exceptions yourself. ABAP Unit simply handles the exception and presents it as an exception error.* Runtime error: Runtime errors are the really bad errors. These errors are completely unexpected (so of course we dont expect to find one in our test example!). When you run a unit test in the development environment, ABAP Unit doesnt catch runtime errors. Instead, you see the short dump view of the runtime error just as if you executed the program normally. The runtime error analysis provides detailed information to help you identify and resolve the problem. In a mass testing scenario, however, you dont want the test run to crash if one test produces a runtime error. Therefore, when you run an ABAP Unit mass test from the ABAP Code Inspector tool, in that context ABAP Unit is able to catch and process runtime errors. Warning: Warnings are messages that dont really indicate a problem in your tested code. Instead, they warn you about improper use of ABAP Unit. The following examples give you a sense of what warnings tell you: The message Test Program '<Name>' Could Not Be Generated could signify a syntax error in your program. The message Constructor of Test Class '<Name>' Must Not Have Parameters indicates that ABAP Unit cant run the test class, because the ABAP Unit driver can only obtain an instance of a test class if its constructor doesnt have any parameters. Although syntactically correct, the test class is not executable. To fix this warning, remove the parameters from the test class constructor.

* Refer to the sidebar Exception Handling in Test Methods on page 16 for more information about class-based exceptions and how to handle them.

On the upper right, you see the error message pane. It lists all errors associated with your selection in the tree display on the left. For example, if you select the test task at the top of the tree, you see all messages produced by the test run. If you select an individual test method, you only see the messages raised in that method. For assertion errors, the Message Text column contains what you passed in the assertion method for the MSG parameter. Exception errors and runtime errors display the exception type. Warnings display the warning message. Double-click on any message to see its detail analysis. On the lower right, you see the detail analysis

pane. Error analysis information appears under the Info node, and the error location appears under the Stack node. The error analysis provides an explanation of the error message, indicating why ABAP Unit concluded that the error occurred. For assertion errors, this analysis describes why the assertion failed. For example, if you compare two strings with the ASSERT_EQUALS method, the error analysis indicates at what position and by what contents they differ. For exception errors, this analysis shows the message of the raised exception. In the case of warnings, you can possibly find some more detail information here. In the case of assertion errors, the analysis can obviously get quite extensive when comparing

26

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

objects with complex data types. You saw a good example of this complexity back in Figure 8. The last line below the Info node usually shows the location, program, class, and method (if available) where the error occurred. Below the Stack node, you find the test-relevant stack information, the program and line that guide you to the error location. Double-click on any line in the error stack to navigate directly to the relevant line of code in the appropriate editor. You now have all the knowledge you need to write and run unit tests. But there are a few more ABAP Unit capabilities you can take advantage of to improve your test design. Well take a look at these next.

production code. In general, take as much care with test code as you would with production code, even though it is only for test purposes. What does isolation mean in the context of a test class? It means that the test fixture the set of well-known test objects, meaning the data and resources needed for a test is ideally exclusive to each test in order to prevent tests from interfering with each other. Otherwise, one test could modify the test fixture in a way for which the next test is not prepared. When introducing new test methods later, you could inadvertently change the behavior of existing test methods without being aware. Basically, you need a clear and repeatable initial state of the fixture used for each test.

Test Isolation
When introducing the unit test concept, I indicated that you first identify a distinct unit of the program that can be tested in isolation. Respecting this isolation is important for several reasons: If a completely isolated test fails, you can easily locate the problem without analyzing any unfamiliar code dependencies. Tests shouldnt interact with other tests, because an individual test might either fail more frequently due to its dependencies, or simultaneously drag many other tests to failure. This process not only distracts you from the real source of the problem, but being showered with unnecessary errors is seriously discouraging!

Test Fixtures in ABAP Unit


ABAP Unit enforces certain principles with respect to this isolation. Each test method automatically gets its own newly created test instance. Therefore, changing the instance in one test doesnt affect any other test. Still, two methods of the same test class could share class attributes. This possibility is restricted to test methods within the same test class by running all test methods of a test class in an isolated test session. Never modify shared class resources in test methods, because this technique is difficult and error prone. An intentional modification of a shared class resource would typically depend on a certain execution order of the test methods, which isnt supported. The test fixture consists of two components: The class fixture refers to static data that exists once for a test class. The instance fixture exists once for each instance of a test class.

In addition, isolation means not relying on any particular test execution order. Even though a specific test order may be respected in single test runs, the situation might be different in mass testing for performance issues with parallelization. Thus ABAP Unit has no guaranteed execution order for test methods! Finally, isolation also means taking great care and attention when accessing common resources, particularly with database accesses. You must take into account the possibility of other tests accessing the same resource. Apply the same measures to make concurrent access safe in test code as you would in

How do you initialize the class and instance fixtures? Performing this task clearly depends on a dedicated execution point in the test sequence. The class fixture initialization that provides commonly used class data and resources must be reached before running the first test method. Sometimes you also

For site licenses and volume subscriptions, call 1-781-751-8799.

27

SAP Professional Journal

January/February 2005

need to clean up provided resources when no longer needed. Therefore, you also need a second execution point in the test sequence for triggering the cleanup, which can only happen after executing all the tests of one test class. Lets examine the situation for the instance fixture. Think of a typical test. You usually need test data for modification or deletion. The test example in this article provides a good illustration. All tests need an instance of the tested CL_AIR_CARRIERS class. Defining this class as a class field isnt meaningful. While many tests could modify its state, you need a defined initial state of this instance in order to create repeatable tests. Alternatively, you could create an instance of the CL_AIR_CARRIERS class at the beginning of each test method. While this approach might be manageable in the simple test example (the test_class definition from earlier in the article), because a single statement constructs this instance, it is inconvenient and means unnecessary redundancy. (Defining the object reference CUT as an object member, rather than as a local variable in each method, already eliminated one line per method.) You can easily imagine that common data setup can be much more extensive and, based on experience, require much more code than the actual test itself. Thus, having a designated shared execution point in the test execution sequence before and after the execution of each test method would be very helpful. Not surprisingly, ABAP Unit supports such execution points, which are respectively referred to as SETUP and TEARDOWN execution points. Before examining where and how ABAP Unit offers these execution points, and how to use them, lets outline the test execution sequence. Translating the isolation measures and the identified consequences into an execution sequence produces the test execution structure shown in Figure 14. Note that the SETUP and TEARDOWN execution points are optional. If you dont need them and dont implement them, ABAP Unit simply ignores them. Optional steps

Figure 14

Execution Algorithm

Start Internal Session for Test Class Class Construction of Test Class Set Up Class Fixture For Each Test Method Create Test Instance Set Up Instance Fixture Run Test Method Tear Down Instance Fixture Tear Down Class Fixture

have a white background; required steps have a gray background.14 This execution sequence applies only if your test class provides specific methods with a specific name and signature. The instance fixture methods are SETUP and TEARDOWN, and the class fixture methods are CLASS_SETUP and CLASS_TEARDOWN. Both the instance and class fixture methods must be private with no parameters. A syntax check warns you if you try to declare fixture methods in a protected or public section. (See the sidebar on the next page for more on inheritance and fixture methods.)

Adding a Test Fixture to the Test Example


Suppose you want to further refine the test example to check what happens if the same airline is added twice.
14

The Nassi-Shneiderman diagram shown in Figure 14 is a graphical method of representing algorithms that is easy to read even if you arent familiar with this diagram type. It signals the control flow of the algorithm from top to bottom. Unlike a program flow diagram, it has no connectors. The example in Figure 14 uses only two diagram symbols the process symbol represented by a rectangle, and the iteration symbol indicating a loop, represented by the lefthand portion of the rectangle that spans all processes encompassed within the loop. It clearly shows the scope of the iteration. For more information, refer to the paper Flowchart Techniques for Structure Programming by I. Nassi and B. Shneiderman (available at www.geocities.com/SiliconValley/Way/4748/nsd.html).

28

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

Fixture Method Behavior in Derived Test Classes


Earlier in the article I discussed how you can declare test methods with different visibilities (PUBLIC, PROTECTED, or PRIVATE) in order to express different uses for inheritance or delegation. However, you must always define fixture methods (SETUP, TEARDOWN, CLASS_SETUP, and CLASS_TEARDOWN) in the PRIVATE section of a test class. Only PRIVATE visibility ensures that these methods are directly related to their implementing class. PRIVATE visibility prevents the instance fixture methods (SETUP and TEARDOWN) from being inherited by derived test classes. If you define the SETUP method in a superclass, but not in its derived class, you want the superclass setup to be executed exactly once (to set up the superclass), and not a second time for the derived class. If the SETUP method had PUBLIC or PROTECTED visibility, the derived class would inherit the method and run it a second time (unless the derived class redefines SETUP). Imagine two test classes that implement the private SETUP and TEARDOWN methods and have the following inheritance relationship:
class testclass2 definition inheriting from testclass1 for testing.

The test execution order of the instance fixture methods is as follows: 1. Run SETUP of testclass1. 2. Run SETUP of testclass2. 3. Run the test method of testclass2 (which might be inherited from testclass1). 4. Run TEARDOWN of testclass2. 5. Run TEARDOWN of testclass1. Note that the setup chain is performed from the superclass to its subclasses, and the teardown chain is performed in the opposite direction. If an error occurs in a SETUP method, the teardown chain begins with the TEARDOWN method of the same class. For example, if the SETUP method of testclass1 fails, the TEARDOWN method of testclass1 is called directly afterward. For class fixture methods (CLASS_SETUP and CLASS_TEARDOWN), this situation is more straightforward. In ABAP, you cant redefine static methods. Suppose you define a CLASS_SETUP static method with PUBLIC or PROTECTED visibility somewhere in your test class inheritance hierarchy. You cant define this method a second time because all derived classes use it. Introducing a second CLASS_SETUP method higher in the hierarchy produces a syntax error in the class that defines that method lower in the hierarchy. You can only provide different implementations of the class fixture methods for each test class in an inheritance relationship if you declare them as PRIVATE.

If we had completed our program example, the class CL_AIR_CARRIERS, by adding its implementation, we sooner or later would have had to consider what should happen in this situation. Most likely a list of air

carriers should not contain duplicate entries. Thus if a particular air carrier is added a second time, the object should still contain only one instance of that carrier. Consequently, the unit tests for this purpose should be

For site licenses and volume subscriptions, call 1-781-751-8799.

29

SAP Professional Journal

January/February 2005

Figure 15
method add_carrier_twice. *

Modified Unit Test

[ unchanged part, as in previous listing ] data: SAPproAir type scarr, " an air carrier we can add l_act type i. " the actual number of airlines create an instance of the class under test create object cut. assert initial state l_act = cut->get_count( ). cl_aunit_assert=>assert_equals( act = l_act exp = 0 msg = 'before adding one airline' ). prepare the test data: SAPproAir-carrid = 'S1'. SAPproAir-carrname = 'SAPpro Air'. SAPproAir-currcode = 'USD'. SAPproAir-url = 'http://www.SAPpro.com'. call the method under test twice: cut->add( SAPproAir ). cut->add( SAPproAir ). after adding the same airline twice l_act = cut->get_count( ). cl_aunit_assert=>assert_equals( act = l_act exp = 1 msg = 'after adding the same airline twice' ). endmethod.

very similar to the ones created previously. Copy the complete method from the previous example, rename the method to ADD_CARRIER_TWICE, add one call to the ADD statement, and revise the comments and messages to reflect the changes. Figure 15 shows the (very few) decisive modifications in boldface type. As you can see, this example now contains a lot of duplicate code. However, using the fixture methods enables you to arrange the code more elegantly and avoid

unnecessary duplication. Figure 16 illustrates this approach, which shows the complete test class with two test methods and a shared test setup.15
15

Note that this example doesnt use the TEARDOWN method because it is unnecessary. There is no general rule for deciding when to use one or both of the fixture methods. The SETUP method is often useful for simplifying code and avoiding code duplication, which offers convenience and efficiency. The TEARDOWN method is used less frequently, and then only for a specific functional purpose, such as resetting permanent changes or closing resources.

30

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

Figure 16

Using the Fixture Methods to Avoid Duplicate Code

*---------------------------------------------------------------------* * CLASS test_air_carriers DEFINITION *---------------------------------------------------------------------* class test_air_carriers definition for testing. private section. methods: setup, add_carrier for testing, add_carrier_twice for testing. data: SAPproAir type scarr, " our preferred air carrier cut type ref to cl_air_carriers. endclass. *---------------------------------------------------------------------* * CLASS test_air_carriers IMPLEMENTATION *---------------------------------------------------------------------* class test_air_carriers implementation. method setup. data l_act type i. * create an instance of the class under test create object cut. prepare the test data: SAPproAir-carrid = 'S1'. SAPproAir-carrname = 'SAPproAir'. SAPproAir-currcode = 'USD'. SAPproAir-url = 'http://www.SAPpro.com'. assert initial state l_act = cut->get_count( ). cl_aunit_assert=>assert_equals( act = l_act exp = 0 msg = 'before adding one airline' ). endmethod. method add_carrier. data l_act type i. * actual test coding:
(continued on next page)

For site licenses and volume subscriptions, call 1-781-751-8799.

31

SAP Professional Journal

January/February 2005

Figure 16 (continued)
cut->add( SAPproAir ). * test assertion: l_act = cut->get_count( ). cl_aunit_assert=>assert_equals( act = l_act exp = 1 msg = 'after adding one airline' ). endmethod. method add_carrier_twice. data l_act type i. * actual test coding: cut->add( SAPproAir ). cut->add( SAPproAir ).

test assertion: l_act = cut->get_count( ). cl_aunit_assert=>assert_equals( act = l_act exp = 1 msg = 'after adding one airline twice' ). endmethod. endclass.

Using ABAP Unit in the ABAP Code Inspector for Mass Testing
Until now, I have focused on running tests for individual programs from within the ABAP Workbench. This approach is obviously inadequate for regression testing and quality assurance purposes. Performing mass testing introduces the need for additional capabilities: You want to be able to test many programs in a single test task at the same time.

You need to flexibly configure the object set and choose the programs that you need to test repeatedly, such as all the programs contained in specific packages that belong to your project. Perhaps you also want to run additional static tests at the same time for the same programs. Certainly you expect to repeat this test many times with exactly the same configuration, so you need to be able to store your test configuration. You need to receive a test summary that shows the results of the entire test run.

32

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit

The complete test must run efficiently in order to produce results within a finite time. You need to be able to save your test results for future reference.

Select the line for the program of interest and double-click on it to restore and open the ABAP Unit result display.

To meet these requirements, SAP has integrated ABAP Unit into the ABAP Code Inspector (transaction SCI). Previously, you could only perform static tests with the Code Inspector in other words, source code analysis. With the integration of ABAP Unit, you can now also perform dynamic tests that involve runtime checks. The ABAP Code Inspector offers all the previously listed capabilities, making it perfectly suited for efficient mass testing. For developers who are already familiar with this tool,16 the Code Inspector now includes the following new features as a result of integrating ABAP Unit: The check variant includes a new category (Dynamic Tests) that contains the ABAP Unit tests. Define a Code Inspector check variant and select the ABAP Unit dynamic tests, either exclusively or in combination with other checks. You can then run the unit tests on any configurable object set of your choice. When you run ABAP Unit tests within a Code Inspection,17 the results are translated into the Code Inspector format. However, you can restore the original ABAP Unit result display for any tested program that raises unit test errors. For these programs, the inspection result contains an additional Message Code Summary section.

Conclusion
In this article, I introduced you to ABAP Unit, the new unit test tool for ABAP. I showed you how to use it efficiently in your everyday development work, and shared some insight into the general concepts and benefits of unit testing. The unit testing approach owes its tremendous success to many reasons:

Unit testing saves money.


This important test type integrates very early into the software lifecycle, and it is a known fact that the earlier you find an error, the lower its overall costs will be.

Unit testing stabilizes development.


As part of a fundamental test suite, unit tests ensure the intended behavior of individual components before you build the whole application, which establishes a stable base for development.

Unit testing saves time.


Of course, you must spend some time up front writing the unit tests. But that effort pays off later in many ways. You have fewer bugs and need less time to fix them. Errors that are found by unit testing are found easily. Unit test errors lead you directly to the error location, avoiding time-consuming debugging sessions. And because errors are found early, others dont waste time working with buggy code.

16

For more information about how to use the ABAP Code Inspector, see the SAP Professional Journal articles Evaluating the Quality of Your ABAP Programs and Other Repository Objects with the Code Inspector (January/February 2003) and An Integrated Approach to Troubleshooting Your ABAP Programs: Using Standard SAP Check Tools During Development and Testing (March/April 2004). In the ABAP Code Inspector, a Code Inspection consists of an object set and a check variant. When an inspection is executed, the Code Inspector performs the single checks in the check variant on the objects in the object set. The result is a list of errors, warnings, and information.

Unit testing improves software maintenance.


It helps you avoid making the same error twice. Once an error is detected, write a related unit test that provokes the error. The same test proves the

17

For site licenses and volume subscriptions, call 1-781-751-8799.

33

SAP Professional Journal

January/February 2005

successful correction of this error and also ensures that the error is never reintroduced.

Developers like unit testing.


Well, maybe they dont at first. But they are quickly converted once they experience the confidence boost that comes from running a huge set of successful tests after a risky code

modification. Conversely, they also see the benefits when those tests fail, and they realize that they just found an error that would otherwise have been missed. But I almost forgot to mention the biggest benefit of all the purpose of testing in the first place, which is the means to achieve the highest possible software quality!

34

www.SAPpro.com

2005 SAP Professional Journal. Reproduction prohibited. All rights reserved.

You might also like