+ All Categories
Home > Documents > Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with...

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

Date post: 03-Apr-2018
Category:
Upload: scribdhome
View: 227 times
Download: 1 times
Share this document with a friend

of 32

Transcript
  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    1/32

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

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

    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, andmaintenance of various test

    tools for ABAP, C/C++, and

    Java, including ABAP Unit.

    Jrgen can be reached at

    [email protected].

    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.

    Attention ABAP Developers!

    Boost the Quality of Your Programs

    by Writing Automated Unit Tests

    with ABAP Unit

    J rgen Staader

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    2/32

    SAP Professional J ournal J anuary/February 2005

    4 www.SAPpro.com 2005 SAP Professional J ournal. Reproduction prohibited. All rights reserved.

    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 test-ing. Then, well look at ABAP Unit itself and how

    it works, including how to create, run, and interpret

    unit tests.

    Principles and Benefitsof 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 portionof 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.

    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 phaseis that you find bugs comparatively late in the proj-

    ect. 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 increas-

    ingly more complete and complex as the implemen-

    tation 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 implemen-

    tation 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 well-

    covered by the extended Computer Aided Test Tool

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

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

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    3/32

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

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

    (eCATT),3 there has been no tool support for auto-

    mated 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.

    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 aunit 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 auto-

    mated, 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 testsconsist of writing temporary test fragments and

    debugging. Many developers also use tracing, or a

    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 informa-tion you need to analyze. Because it is difficult to

    anticipate which specific details are useful, you typi-

    cally 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 guar-

    antee that it will after the next few development itera-

    tions, 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 both-

    ered with testing a piece of code after you have deter-

    mined 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 guar-

    antees once-working functionality is never broken by

    a later modification (also known as regression test-

    ing), and in turn reduces the amount of hiddenextra testing effort you need to expend during devel-

    opment. 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 Beneficial forMaintenance, Too

    I have emphasized the advantages of being able to test

    early and often during development. However, thevalue 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

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

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    4/32

    SAP Professional J ournal J anuary/February 2005

    6 www.SAPpro.com 2005 SAP Professional J ournal. Reproduction prohibited. All rights reserved.

    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.

    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 workfor 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 con-

    sists of:

    The ability to write a unit test in ABAP with des-

    ignated test classes and test methods

    Commands to run unit tests on programs fromwithin 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

    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 pro-

    gram types:

    Four Steps to Creating a Unit Test

    1. Consider what you want to test (that is,

    the unit to be tested), such as a functionmodule or a specific method of a class.This tested code belongs to an ABAPprogram, and its unit test is part of thesame program.

    2. Add the unit test to the program. Youwrite unit tests in ordinary ABAP usingthe editor for the program, such as theABAP Editor (transaction SE38) forreports or the Class Builder (transactionSE24) for global classes.

    3. Run the unit test from the ABAP

    Workbench via the menu commandprovided by the particular editor inuse (Figure 11 later in the articlesummarizes these commands).

    4. Analyze the results in case of failure.Keep in mind that a successful testsimply raises a success message.

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

    5See the article Evaluating the Quality of Your ABAP Programs andOther Repository Objects with the Code Inspector (SAP Professional

    Journal, January/February 2003).

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    5/32

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

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

    Executable programs

    Module pools

    Function groups

    Class pools6

    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 produc-

    tion code and in the test code. There is no real differ-

    ence from a code perspective. You dont need to

    learn a new language for testing and continuallyswitch between production and test languages.

    You implement ABAP Unit test code in test meth-

    ods 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 FORTESTING addition. A test class is simply a local classwith FOR TESTING added to its definition. A testmethod 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 singletest method (test_method):

    class test_class definition for

    testing.private section.methods:

    test_method for testing.endclass.

    Contrary to the test definition, where the FORTESTING addition identifies the test nature of theclasses and methods, the actual test implementation

    is no different from an ordinary production class

    implementation. The only thing you need from thetesting 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.

    6A class pool is the ABAP program frame for a global class. It is auto-matically generated when you create a new global class using the ClassBuilder (transaction SE24). A class pool serves as the container forexactly one global class, therefore, inside a class pool means the sameas inside a global class.

    Private vs. Public SectionDeclarations

    Experienced ABAP Objects programmersmay 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 testmethod of another test class).

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    6/32

    SAP Professional J ournal J anuary/February 2005

    8 www.SAPpro.com 2005 SAP Professional J ournal. Reproduction prohibited. All rights reserved.

    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 havemany test classes, each of which can contain many

    test methods.

    Creating a ProgramExample 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 iscommonly 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

    and SAP documentation for demonstration and training

    purposes. All shipped SAP systems include its corre-

    sponding database tables. Using the Class Builder

    (transaction SE24), create a CL_AIR_CARRIERS

    global class as a simple wrapper for the SCARR data-

    base table. This class applies to air carriers and includes

    methods to add or delete a carrier, obtain the name andWeb address for a specified carrier ID, and retrieve the

    number of all available carriers (see Figure 2).

    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 theADD and

    GET_COUNTmethods 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. TheADD method has one input parameter:

    Figure 1 ABAP Unit Test Hierarchy

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

    Program A Program B

    Test Class D Test Class E

    TestMethodTest

    MethodTestMethod

    TestMethodTest

    MethodTestMethod

    TestMethodTest

    MethodTestMethod

    Test Class B Test Class CTest Class A

    Test Task

    Program C

    The programs being tested (i.e., undertest) are aggregated in a test task

    Test classes belong organizationally andphysically to the program under test

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    7/32

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

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

    importing AIRLINE type SCARR

    The GET_COUNTmethod returns the following

    result:

    returning value(RESULT) type I.

    This will probably surprise you, but you can ignorethe 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 imple-

    mentation 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 pro-

    duce. Quite simply, you are finished when all yourtests 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).

    Figure 2 Example CL_AIR_CARRIERS Class Definition

    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 collectivecode 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)

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    8/32

    SAP Professional J ournal J anuary/February 2005

    10 www.SAPpro.com 2005 SAP Professional J ournal. Reproduction prohibited. All rights reserved.

    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 sepa-

    rated 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 pro-

    duction and test code complicates this fundamental

    prerequisite. Keeping the production and test code

    synchronized requires care and effort. Suppose some-

    one changes the production code at some point in the

    future. Might that person overlook the separate test

    program associated with that code? (In an idealworld, appropriate test code exists for all production

    code!) When the tests eventually fail, is the unfortu-

    nate 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 ofFigure 3 illustrates this situation and

    its potential problems.

    The depiction of these difficulties imply what you

    really need a common compilation unit for both

    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 theirvalue. 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 productioncode 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 providethe 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 havefinished the implementation when you cant identify any.

    (continued from previous page)

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    9/32

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

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

    production and test code. All the noted problems van-

    ish 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 produc-

    tion 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

    Figure 3 External vs. Internal Test Code

    Traditional Approach: Production Code andTest Code in Separate Compilation Units

    Limitation: External view with limited accessto the implementation.

    Problem: Version synchronization. Is there amatching test version for the production codeversion? Which is the matching test version?

    Problem: Transport synchronization. Will thematching versions of the test and productioncode arrive together at their destinations?

    ProductionCode

    TestCode

    ProductionCode

    Version X

    ProductionCodeVersion Y

    ProductionCode

    Version Z

    TestCode

    Version Z

    TestCode

    Version X

    ProductionCode Transport

    TestCode Transport

    TestCode

    ProductionCode

    New Approach: Production Code and TestCode in a Common Compilation Unit

    Internal view with unlimited access to theimplementation.

    Version synchronization is not a problem.The test code is embedded within theproduction code.

    No transport synchronization is necessary.The test code always comes along with theproduction code.

    Test CodeVersion X

    ProductionCode Version X

    Test CodeVersion Z

    ProductionCode Version Z

    Production Code

    Test Code

    CommonCode Transport

    Production Code

    Test Code

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    10/32

    SAP Professional J ournal J anuary/February 2005

    12 www.SAPpro.com 2005 SAP Professional J ournal. Reproduction prohibited. All rights reserved.

    unacceptable in a production system for example,

    test operations might need to access the database or

    even manipulate or delete database content. For theseperformance 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 pro-

    gram 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 sim-

    ply 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 devel-opment system where the tests are part of the pro-

    gram 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 thatraises 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 com-

    pilation 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 typesLocal

    class implementations in the Class Builder).7

    Our example global class CL_AIR_CARRIERSis 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.

    Figure 4 Program Load Without Test Code

    Production Code

    Test Code

    Figure 5 No Access to Test Code

    Production Code No access from productioncode to test code

    Full access from test codeto production code

    Test Code

    7You can put isolated, independent test classes in their entirety (that is,both the class definition and implementation) in the local class imple-mentations section via this menu path. Alternatively, you can put thetest class definition in the local class definitions section via the menupath Goto Class-local typesLocal class definitions/types. If yourtest classes have dependencies (that is, if you are using test inheritanceor delegation), always put the test class definitions in the local class def-initions section.

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    11/32

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

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

    Now were ready to create a unit test for the classwe created back in Figure 2. Lets start by testing the

    ADD method, beginning with the test definition. Openthe local implementation of the class under test (in this

    case, CL_AIR_CARRIERS), and enter the followingtest definition:

    class test_air_carriers definition

    for testing.private section.

    methods:add_carrier for testing.

    data:cut type ref tocl_air_carriers.

    endclass.

    Compared to the first test example (the earlier

    test_class definition), notice that this example

    contains additional test data designed to avoid redun-dancy when you add more test methods. This code

    fragment defines a reference (CUT) to the class undertest simply for accessing this instance. Defining this

    reference once as a member of this class is more effi-

    cient than defining it separately in every test method.

    Next, supply the corresponding test implementa-

    tion 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 cansee, the implementation part doesnt contain any test-

    specific syntax. It could just as well be production

    Figure 6 The Test Implementation

    8Note that SAP Professional Journal has not invested in air carriers forcloser contact with its international SAP community. This example usesa fictitious air carrier to avert suspicion of surreptitious advertising.

    class test_air_carriers implementation.

    method add_carrier.

    data:

    SAPproAir type scarr, " an air carrier we can addl_act type i. " 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.

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    12/32

    SAP Professional J ournal J anuary/February 2005

    14 www.SAPpro.com 2005 SAP Professional J ournal. Reproduction prohibited. All rights reserved.

    code. Nevertheless, you wouldnt notice whether

    theADD method executed correctly because youhave 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 asser-tion methods as part of its CL_AUNIT_ASSERTservice class for this purpose, which we will look at in

    detail next.

    Verifying Test Assertions

    The CL_AUNIT_ASSERT service class providesseveral 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 Unitresult 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 under-

    stand what each of them do. Lets take a closer look

    at each in turn.

    Understanding the Assertion MethodParameters

    Lets start by reviewing the common parameters of allassertion methods. They all support the following

    optional parameters:

    MSG is a message of type CSEQUENCE thatidentifies 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 ofTOLERABLE, CRITICAL,

    or FATAL, as defined in theIF_AUNIT_CONSTANTS interface and aliasedin the CL_AUNIT_ASSERT class. This parame-ter has theAUNIT_LEVEL dictionary type, and

    its default value is CRITICAL. The ABAP Unitresult display reflects this prioritization, whichis particularly helpful during mass testing for

    judging the significance of a unit test error and

    prioritizing follow-up efforts. FATAL unit testerrors should obviously cause more alarm than

    TOLERABLE errors. Regardless, your goalshould 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 ofNO, METHOD,CLASS, or PROGRAM. This parameter has theAUNIT_FLOWCTRL dictionary type, and its

    default value is METHOD. The possible valuesfor this parameter are defined in the

    IF_AUNIT_CONSTANTS interface and aliasedin the CL_AUNIT_ASSERT class:

    - NO means do not interrupt the test when anerror occurs and continue the test with the

    statement that follows the failed assertion.

    - METHOD means stop executing the testmethod when an error occurs. Remember that

    the purpose of the test is to prove the correct-

    ness 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 executionand continue the test with the next test class.

    - PROGRAM means the error is so serious thatcontinuing 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.

    Some assertion methods also support one or more

    of the following parameters:9 Note that optional applies to the ABAP signature extension, as well as

    whether a default value is specified in the signature.

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    13/32

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

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

    ACT is the actual value of the assertion

    verification, and is required by all of the assertion

    methods except for FAIL. Pass the actual valueor reference that you want to check. The type is

    usuallyANY, except forASSERT_DIFFERS(type SIMPLE) andASSERT_SUBRC (typeSYSUBRC).

    EXP is the corresponding expected value for

    assertions that compare the expected value with

    the actual value. It is required by the assertion

    methodsASSERT_EQUALS (typeANY) andASSERT_DIFFERS (type SIMPLE), and is

    optional for the assertion method

    ASSERT_SUBRC (type SYSUBRC).

    Figure 7 ABAP Assertion Methods

    Method Purpose Required Parameters Optional Parameters andParameters with Default Values

    ASSERT_BOUND Ensure the validity of thereference for a referencevariable

    ACT typeANY MSG type CSEQUENCELEVEL typeAUNIT_LEVEL*QUIT typeAUNIT_FLOWCTRL**

    ASSERT_DIFFERS Ensure the differencebetween two simple data

    objects (since SAP WebAS SP4 only)

    ACT type SIMPLEEXP type SIMPLE

    MSG type CSEQUENCELEVEL typeAUNIT_LEVEL*

    TOL type FQUIT typeAUNIT_FLOWCTRL**

    ASSERT_EQUALS Ensure the equality of

    two data objects

    ACT typeANY

    EXP typeANY

    MSG type CSEQUENCE

    LEVEL typeAUNIT_LEVEL*TOL type F

    QUIT typeAUNIT_FLOWCTRL**

    ASSERT_INITIAL Ensure that an objecthas its initial value

    ACT typeANY MSG type CSEQUENCELEVEL typeAUNIT_LEVEL*

    QUIT typeAUNIT_FLOWCTRL**

    ASSERT_NOT_BOUND Ensure the invalidity

    of the reference for areference variable

    ACT typeANY MSG type CSEQUENCE

    LEVEL typeAUNIT_LEVEL*QUIT typeAUNIT_FLOWCTRL**

    ASSERT_NOT_INITIAL

    Ensure that an object

    does not have its initialvalue

    ACT typeANY MSG type CSEQUENCE

    LEVEL typeAUNIT_LEVEL*QUIT typeAUNIT_FLOWCTRL**

    ASSERT_SUBRC Expect a distinct value

    for the return codeSY-SUBRC (since SAPWeb AS SP4 only)

    ACT type SYSUBRC

    EXP type SYSUBRC

    MSG type CSEQUENCE

    LEVEL typeAUNIT_LEVEL*QUIT typeAUNIT_FLOWCTRL**

    FAIL Terminate the test withan error

    None MSG type CSEQUENCELEVEL typeAUNIT_LEVEL*

    QUIT typeAUNIT_FLOWCTRL**DETAIL type CSEQUENCE

    * 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.

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    14/32

    SAP Professional J ournal J anuary/February 2005

    16 www.SAPpro.com 2005 SAP Professional J ournal. Reproduction prohibited. All rights reserved.

    TOL is the tolerance (of type f). This optionalparameter applies only to comparisons of floating-

    point numbers (via the assertion methods

    ASSERT_DIFFERS andASSERT_EQUALS).

    DETAIL is an additional detail message (of type

    CSEQUENCE) that further describes the error.This optional parameter applies only to the FAILmethod, 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.

    Using the General-Purpose FAIL AssertionMethod

    FAIL is the simplest and most general assertionmethod. It supports the common parameters MSG,LEVEL, and QUIT, and the optional parameterDETAIL.

    Calling FAIL unconditionally causes an assertionerror. This behavior is different from that of the asser-

    tion methods with the prefixASSERT_, which verifythe specified assertion and indicate an error only if the

    assertion is false. The error notification includes ananalysis of the error with a detailed message that

    describes what is wrong with the assertion. The

    FAIL method doesnt check anything; it merely sig-nals that an error occurred. Although the FAILmethod 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 adescription of the error) and the DETAIL parameter

    (to further explain the error situation). In the ABAPUnit result display, the DETAIL message appears inthe detail section for the error.

    While you can use the FAIL method when youcant adequately express an assertion with the special-

    ized assert methods, it is unlikely that you will

    Exception Handling in Test Methods

    Dont bother handling any unexpected class-based exceptions thrown by tested code. You dont need toenclose 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 toABAP 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 thesource location where the exception was raised.

    If the tested code raises an exception derived from the CX_STATIC_CHECKclass,* the syntax check

    statically checks whether all exceptions that are raised or passed from a called procedure are eitherhandled 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_CHECKexceptions and class-based exception handling, see the article A ProgrammersGuide to the New Exception-Handling Concept in ABAP in the September/October 2002 issue of SAP Professional Journal.

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    15/32

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

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

    encounter such a scenario. FAIL is commonly usedto verify the flow control of test code. Insert the

    FAIL method in control blocks that should not bepassed through, such as within an if else block:

    IF logical_expression." test something

    else.cl_aunit_assert=>fail( ).

    endif.

    Testing for exceptions also demonstrates a good

    example of using the FAIL method (see the sidebarabove). In practice, this technique is perhaps the most

    important use of the FAIL method.

    Using the Specialized ASSERT_ AssertionMethods

    The assertion methods that are specialized for a partic-

    ular purpose all start with the prefixASSERT_. Eachmethod expresses a specific assertion to be verified

    using built-in error analysis.

    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 informa-

    tion 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 typeANY,

    allowing you to pass data of any type;10 two methods

    (ASSERT_DIFFERS andASSERT_SUBRC) require

    ACT to have a more restricted type (SIMPLE and

    SYSUBRC, respectively).

    Using ASSERT_EQUALS for Comparing

    Expected and Actual Results

    Lets start with the most important, most useful asser-

    tion method,ASSERT_EQUALS. Its usefulness stems

    from the fact that in a test you usually want to compare

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

    ABAP Unit. As shown in the following example, use the CX_STATIC_CHECKabstract superclass todeclare 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 wantto 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 typeCX_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.

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    16/32

    SAP Professional J ournal J anuary/February 2005

    18 www.SAPpro.com 2005 SAP Professional J ournal. Reproduction prohibited. All rights reserved.

    the actual state or result with the expected state or

    result. Thus, in addition to theACT parameter for the

    actual value, this method has a mandatory EXP param-

    eter 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.

    In this example, you examine an imaginary

    CL_FORTUNE_TELLER class to check the qualityof its forecasts in relation to ABAP Unit. Create a

    FORTUNE_TELLER instance of this class and ask itin 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 sim-

    ple 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 argu-

    ments for theASSERT_EQUALSmethod becauseboth values have theANY generic data type. Beforecomparing the values, the method first ensures their

    comparability. Comparability is weaker in this con-

    text than for a direct comparison via the EQUALSoperator in ABAP. In other words, you can compare

    values with ABAP Unit where a direct comparison

    using the ABAP EQUALS operator would fail with aruntime error. For example, you could set up a stan-

    dard 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 val-

    ues differ. For long character sequences, the wildcard

    symbol an asterisk (*) replaces matchingsequences. For instance, suppose you want to com-

    pare the following strings:

    This string is not very long but

    just an example

    and

    This string is not so long butjust an example

    The analysis that appears in the result display

    would provide the following explanation:

    Character String Different as of

    Position 19Expected [*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 dif-

    ferent if a single line is deleted, if lines are in a dif-

    ferent 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 treebranches 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.

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    17/32

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

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

    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 differencesdown 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 eval-

    uate 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 repre-

    sent an infinite amount of real numbers in a finite

    number of bits (or more precisely, in the finite num-

    ber of 64 bits reserved by ABAP for floating-point

    Figure 8 ABAP Unit Detail Analysis for a Table Comparison

    Missingline inexpectedtable

    Analysis down tocomponent of table line

    Sameitem atdifferentindices

    Size and type ofinternal table

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    18/32

    SAP Professional J ournal J anuary/February 2005

    20 www.SAPpro.com 2005 SAP Professional J ournal. Reproduction prohibited. All rights reserved.

    numbers).11 This discrepancy becomes more appar-

    ent because the internal representation is base 2,

    instead of the more familiar base 10 representation.

    In short, an exact comparison of floating-point val-

    ues seldom behaves as expected. Therefore, you

    specify a tolerance for expressing the range in which

    you consider two numbers to be equal. This toler-

    ance 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.

    Using the Other ASSERT_ Methods Effectively

    ABAP Unit provides several additionalASSERT_methods for other specific purposes:

    ASSERT_DIFFERS

    ASSERT_BOUND andASSERT_NOT_BOUND

    ASSERT_INITIAL and

    ASSERT_NOT_INITIAL ASSERT_SUBRC

    TheASSERT_DIFFERSmethod is the oppositeof theASSERT_EQUALSmethod, with the limitationthat 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_DIFFERShas essentially the same parameter list and semantics

    asASSERT_EQUALS, except for the EXP parameter(which in this context really means not expected).

    Continuing the fortune teller example from theASSERT_EQUALS discussion, the example in

    Figure 9 uses theASSERT_DIFFERSmethod tocheck whether the fortune teller has a standard answer

    to any question asking for a certain year. (For sim-

    plicity, I excluded the declaration and creation sec-

    tions.) Unless you are not completely new to

    programming, this assertion should evaluate to true.

    TheASSERT_DIFFERSmethod is one of thetwo exceptions where theACT parameter doesnt have

    the generic ABAP typeANY instead,ACT and EXPhave the type SIMPLE. This limitation is due to theplausibility 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

    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.

    11Floating-point numbers are displayed internally with 16 decimal placesaccording to the IEEE-754 standard (double precision). For more informa-tion about floating-point arithmetic, refer to the bookThe Art of ComputerProgramming by Donald E. Knuth, or the paper What Every ComputerScientist Should Know About Floating-Point Arithmetic by DavidGoldberg (available at citeseer.ist.psu.edu/goldberg91what.html).

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    19/32

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

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

    reasons. With simple data types, you can precisely

    specify what you expect to be different.

    TheASSERT_BOUNDmethod verifies that a ref-

    erence variable contains a valid reference. It has thecommon parametersACT, MSG, QUIT, and LEVEL.This method behaves like the ABAP logical expres-

    sion IS BOUND. It supports any type for the actualvalue (theACT parameter). However, the assertiononly passes if you pass data or an object typed with

    REF TO. Otherwise, an error is launched.

    TheASSERT_NOT_BOUNDmethod (which isthe opposite of theASSERT_BOUNDmethod) verifiesthat a reference variable does not contain a valid refer-

    ence. It has the common parametersACT, MSG,

    QUIT, and LEVEL. This method behaves like theABAP logical expression IS NOT BOUND. For theactual value (theACT parameter), you must pass dataor an object typed with REF TO. Otherwise, an erroris launched.

    TheASSERT_INITIALmethod verifies that theactual value is initial i.e., that it contains its type-

    specific initial value. It has the common parameters

    ACT, MSG, QUIT, and LEVEL. This method behaveslike the ABAP logical expression IS INITIAL.

    TheASSERT_NOT_INITIAL method (which isthe opposite of theASSERT_INITIALmethod) veri-fies that the actual value is not initial in other

    words, that it contains a different value than its type-

    specific initial value. It has the common parameters

    ACT, MSG, QUIT, and LEVEL. This method behaveslike the ABAP logical expression IS NOT INITIAL.

    Starting with SAP Web AS SP4, the new

    ASSERT_SUBRCmethod allows you to verify thestate of the SY-SUBRC system field.12 After callinga statement that sets SY-SUBRC, it is sensible pro-

    gramming practice to check its content before con-

    tinuing the process. However, you cant easily

    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 unneces-

    sary with ASSERT_SUBRC, because with thismethod 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 expli-

    citly test a failure situation in which you expect

    SY-SUBRC to have a value other than zero.

    Checking the value ofSY-SUBRC is not the

    only benefit of this method. Often, non-class-based

    exceptions are used with ABAP messages (using theMESSAGE RAISING statement). Based on current

    practices, you typically raise a message if a non-

    class-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 mes-

    sage in the detail view for the error.

    Choosing an Assertion Method for the ExampleUnit Test

    Armed with an understanding of the assertion

    12 SY-SUBRC is an important system field that contains the return codeset by many ABAP statements. It is set to zero if the statement was suc-cessfully executed. Any other value signals a problem. Different valuesofSY-SUBRC are associated with different errors. See the ABAPonline documentation for further details.

    13In the other assertion methods, all actual and expected values arepassed by reference (rather than by value) due to the generic natureof these values. Since anticipating the type of object to be passed isimpossible, general copying could introduce performance problemswhen passing huge tables or structures as parameters to the assertionmethods.

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    20/32

    SAP Professional J ournal J anuary/February 2005

    22 www.SAPpro.com 2005 SAP Professional J ournal. Reproduction prohibited. All rights reserved.

    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 exam-ple,ASSERT_EQUALS.

    After calling theADD method in theADD_CARRIER test method in the example test

    implementation (Figure 6), you want to obtain the

    actual value and compare it to the expected value. Inthis 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_actexp = 1

    msg = 'after adding one ' &'airline'

    ).

    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_COUNTmethod

    really returned 0 before adding the 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 carri-

    ers). 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 theADD method presumes that theGET_COUNTmethod 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 dedi-

    cated 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 typi-

    cally 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 effi-

    ciency. Experience also shows that developers are

    Figure 10 The Complete Test Implementation

    method add_carrier.

    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_actexp = 0msg = 'before adding one airline'

    ).

    * prepare the test data:

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    21/32

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

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

    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.

    SAPproAir-carrid = 'S1'.SAPproAir-carrname = 'SAPpro Air'.SAPproAir-currcode = 'USD'.SAPproAir-url = '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_actexp = 1msg = 'after adding one airline'

    ).

    endmethod.

    Figure 11 How to Run ABAP Unit Tests

    Tool (Transaction) View Menu Path

    ABAP Editor (SE38) Initial Screen Program Execute Unit Test

    Display Program Test Unit Test

    Function Builder (SE37) Initial Screen Function Module Test Unit Test

    Display Function Module Test Unit Test

    Class Builder (SE24) Initial Screen Object type Unit Test

    Class Definition Class Unit Test

    Method Def. Method Unit Test

    Public/Prot./Priv. Section Public/Prot./Priv. section Unit TestClass-local types Local types Unit Test

    Loc. class implem. Unit TestMacros Unit Test

    Object Navigator (SE80) Context menu on variousprogram types and parts of it

    Unit TestExecute Unit Test

    TestUnit Test

    Figure 10 (continued)

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    22/32

    SAP Professional J ournal J anuary/February 2005

    24 www.SAPpro.com 2005 SAP Professional J ournal. Reproduction prohibited. All rights reserved.

    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

    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.

    Interpreting Unit Test Results inthe 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 con-

    sists 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

    with all its contained test classes and their contained

    test methods. This test hierarchy for a test run is cre-

    ated 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 individualtest 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 belowthat 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 pro-

    duced TOLERABLE errors.

    A red square means that the test produced at least

    one CRITICAL or FATAL error.

    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 speci-

    fied for the LEVEL parameter (FATAL, CRITICAL,

    Figure 12 Successful Test Message in Status Bar

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    23/32

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

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

    or TOLERABLE), as described earlier in the section onthe 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 (asser-

    tion error, exception error, runtime error, or warning).

    Figure 13 ABAP Unit Result View

    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 testmethod (Figure 10), the secondASSERT_EQUALS verification checks if theADD method doesnt exe-

    cute properly and fails to add the airline. Of course, checking the counter is a rather weak testfor 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 theinstance does some complex things that could fail and raise an exception, such as retrieving data

    (continued on next page)

    Test Result Overview Message Details

    Error Messages

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    24/32

    SAP Professional J ournal J anuary/February 2005

    26 www.SAPpro.com 2005 SAP Professional J ournal. Reproduction prohibited. All rights reserved.

    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. Exceptionerrors 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 explana-

    tion 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_EQUALSmethod, the error analysis indi-cates at what position and by what contents they dif-

    fer. For exception errors, this analysis shows the

    message of the raised exception. In the case of warn-

    ings, you can possibly find some more detail informa-

    tion here. In the case of assertion errors, the analysis

    can obviously get quite extensive when comparing

    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 needto catch any exceptions yourself. ABAP Unit simply handles the exception and presents it as anexception 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 shortdump 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 masstesting 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 whatwarnings tell you:

    - The message Test Program '' Could Not Be Generated could signify a syntax error inyour program.

    - The message Constructor of Test Class '' Must Not Have Parameters indicates thatABAP Unit cant run the test class, because the ABAP Unit driver can only obtain an instance of atest 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.

    (continued from previous page)

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

    to handle them.

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    25/32

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

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

    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 thetest-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.

    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 isola-

    tion is important for several reasons:

    If a completely isolated test fails, you can easily

    locate the problem without analyzing any unfamil-

    iar code dependencies.

    Tests shouldnt interact with other tests, because

    an individual test might either fail more frequentlydue 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!

    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 sit-

    uation might be different in mass testing for perfor-

    mance 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, particu-

    larly 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

    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 pre-

    pared. 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 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.

    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

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    26/32

    SAP Professional J ournal J anuary/February 2005

    28 www.SAPpro.com 2005 SAP Professional J ournal. Reproduction prohibited. All rights reserved.

    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 fix-

    ture. 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 eachtest method. While this approach might be manage-

    able in the simple test example (the test_classdefinition 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 thanas a local variable in each method, already eliminated

    one line per method.)

    You can easily imagine that common datasetup 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 help-

    ful. Not surprisingly, ABAP Unit supports such exe-

    cution 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 consequen-

    ces into an execution sequence produces the test exe-

    cution 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

    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 methodsare CLASS_SETUP and CLASS_TEARDOWN. Boththe instance and class fixture methods must be pri-

    vate 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.

    14The Nassi-Shneiderman diagram shown in Figure 14 is a graphical

    method of representing algorithms that is easy to read even if youarent familiar with this diagram type. It signals the control flowof the algorithm from top to bottom. Unlike a program flow diagram,it has no connectors. The example in Figure 14 uses only twodiagram symbols the process symbol represented by a rectangle,and the iteration symbol indicating a loop, represented by the left-hand portion of the rectangle that spans all processes encompassedwithin the loop. It clearly shows the scope of the iteration. Formore information, refer to the paper Flowchart Techniques forStructure Programming by I. Nassi and B. Shneiderman (availableat www.geocities.com/SiliconValley/Way/4748/nsd.html).

    Figure 14 Execution Algorithm

    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

    Start Internal Session for Test Class

  • 7/29/2019 Attention ABAP Developers! Boost the Quality of Your Programs by Writing Automated Unit Tests with ABAP Unit.pdf

    27/32

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

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

    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

    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, youmust 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 relatedto 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, youwant the superclass setup to be executed exactly once (to set up the superclass), and not a second timefor 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 SETU


Recommended