Have you ever thought of how important is testing in our life? For instance, imagine we build a car and fit together all the pieces without even testing a single part of it. Then, when the construction is finished, we enroll in a car race, expecting it to function as designed. Do you think the engine will even start? I think we have reason to doubt it.
Therefore, what can be more satisfying than testing our products and fixing the errors to ensure the delivered quality to the customers? In the field of software development this activity is known as the so-called error analysis.
The today’s article is the first from a two part series which focuses on leveraging the ABAP Unit framework in Eclipse. This first theoretical part offers you the necessary know-how for building Unit Test Cases for the source code using a practical example. In the second part we will demonstrate the exact procedure based on a practical example.
Why test an application?
A project lifecycle involves many procedures and stages to be followed in a methodical way. As software developers, we should be aware, that there is always the need of testing a product during the development and integration phases of an application. Our goal for it is to last for a long period of time and to perform resourcefully.
Testing is essential and offers several advantages:
- less defects leading to the improvement of overall capacity and accuracy
- it is more cost effective related to future developments
- improves the quality and ensures the application performance
- encourages customer’s satisfaction and confidence
- keeps your position in the business field competition
Computer systems are often complex and hard to understand. As a result, various methodologies have been implemented to evaluate the behaviour of a product. In the light of testing our software code, there are several testing practices used along the lifecycle of an application, as presented below:
Figure 1: Testing practices used along the lifecycle of an application
It is the first level of software testing where individual units of code are tested to see if they work as expected. Consequently, each piece of code is subjected to a series of test cases. It can be performed manually, but usually tests are automated.
It is a technique focused to test the integration of different modules that were previously unit tested by grouping them in multiple ways and to check their behaviour and data communication. Tests are defined in an integration test plan and applied to these aggregated components.
It is a testing technique that focuses on the UI (User Interface) design structure. Can be executed manually or by using automated tools. It is a practice used to confirm the properties and acknowledge the state of the UI elements. This can be effectively achieved by creating a diversity and combination of test cases.
It unscripts the Quality Assurance (QA) technique used to investigate and discover what works and what does not work in an application. Testers have the possibility to explore, learn and check the application in real-time. Test cases are not necessary beforehand, usually testers decide on the fly what to test next and how much time to spend on a particular functionality.
Except for the Unit Testing technique, when testing an application the inside details of it are seen as a „black box” for the tester. Nonetheless, as prerequisites there should exist a basic understanding of the system design.
Automated Testing versus Manual Testing
First and foremost, what is automated testing and how can we define the manual testing?
Automated testing is a process of testing the software code by running a minimum set of scripted tests. These tests are executed using an automated tool that will eventually report the actual values and compare the results with the expected outcome. The aim of the automated testing is to minimize as much as possible the effort and the time consumed. This technique is appropriate and convenient for large projects, particularly if they are too complex to rely only on manual testing.
Manual testing , on the other hand, is a technique of finding errors and defects in a software application by performing a suite of test cases by a human. It is not necessary to have knowledge of an intermediary automated tool, but it may be very time-consuming taking into consideratio, that, to ensure the completeness of testing, testers need to a create a suitable schema that will lead to a detailed set of important test cases to be covered.
It would be ideal in the first place to manually test the code of a new application or after any major change of it and then to create new automated tests for a better coverage and understanding of the implemented functionalities.
Having said that, chances are that there we will be the need to combine automated testing with manual testing in order to provide a complete and fully covered test plan. The reality is, there is no ”better” or ”worse” procedure, they are just different.
What is Unit Testing and when should we use it?
Let us start by answering the second question. The suitable response would be: everytime we want to test a small unit and its behaviour. You may be wondering what is a unit then?
A ”unit” is defined as the smallest testable component of an application, such as a class or a method, that can be isolated from the rest of the code and controlled to investigate if it fits for use.
As opposed to the other testing techniques, there is a need for a solid understanding of the system architecture when using ABAP Unit Testing. Therefore, Unit Testing is also referred to as a „white” or „gray box” testing and consequently, unit tests should be created and defined by a developer.
Most programming languages have designated unit testing frameworks and so does ABAP. Here, all the background processes required for testing are built into an IDE (Integrated Development Environment), a fact that enables us to execute the unit tests with every compile of the test program.
The most suitable tool in SAP for Unit Testing is the ABAP Unit Framework in Eclipse IDE. This framework is part of the ABAP Development Tools (ADT), therefore, the only thing you need to do is to install the add-on into your Eclipse platform. For those who do not have it installed, yet, you can find more information along with a step-by-step tutorial on this blog article.
Unit tests do not interact with the environment or with external systems of the codebase. They are always running in a simulated and isolated environment, in most of the cases, as a separated program in which unit tests are defined as test methods in local test classes. Thus, when the application changes in the real, productive environment, the unit part will not be automatically informed due to isolation from the system.
In order to make your tests effective, you need to structure the code in a way that makes it easy to unit test. Nevertheless, it requires a bit of practice to get good at it and to understand what to test in isolation.
Unit testing should be applied where tests have a clear meaning. The Business Layer code is commonly suitable for running tests and, hence, it represents the main area where unit testing is focused.
Our goal is to write efficient automated tests alongside with testable code. For instance, when running unit tests we have the flexibility to change the source code and to adjust it to fix the errors and to make it testable. Above all, the most obvious benefit is knowing down the road that when a change is made no other individual units of code are affected.
Figure 2: Writing efficient automated tests
Advantages and benefits
Naturally, as the first level of performing test cases in an application, unit testing provide some notable advantages. Not only that, when having a proper setup, unit tests are:
- Fast – typically can be run thousands of tests/second
- Simple – unit tests focus on small parts of the application
- Timely – tests are written alternatively with the product code
But also, Unit Tests are very effective because they provide:
- Major code coverage – in many cases up to 80-90% code coverage
- Easy error analysis – unit tests point exactly to the place where the code goes wrong
- Stability – unit test repeatability result in a constant behaviour, fact which makes them stable.
Creating a Test Class
In the SAP field, unit tests have been introduced as part of the Object-Oriented design. On that consideration, we can intuitively notice that unit tests work perfectly with classes. In a scenario where we are not able to test all of the report flow, we should at least try to unit test small parts of it.
Moreover, we should only test the public interface of an application and not the private parts. Normally, we are not allowed to test directly blocks of a report, as INITIALIZATION or START-OF-SELECTION, but we can implement the same logic by converting these into object methods and test them afterwards. Worth to notice here is that modularization is very important for a better programming.
The idea is that we define and implement test classes in the same way we define a regular ABAP Objects class. However, what makes a difference is the ”FOR TESTING” statement we have to add to the test class definition. Keep in mind that this addition basically separates the application into two different parts: the test code and the production code.
Even though there is not a standard naming convention yet official, SAP suggests us to add a prefix to the test classes names as in ”LTC_<class_name>”, in order to emphasize that they are local test classes and to distinguish their focus. Moreover, what we also need to specify for a test class are the two class attributes, RISK LEVEL and DURATION, used by the ABAP Unit runner to interpret the properties of that class.
The RISK LEVEL attribute is referring to the side effects that could impact the system:
- HARMLESS – no existing process will be affected by the unit test
- DANGEROUS – the unit test could make changes to a database or persistent data
- CRITICAL – both customization and persistent data could be modified
Kindly keep in mind that every unit test should be defined with the scope of being ”harmless”, hence not to modify the environment in any way.
The DURATION attribute is referring to the expected execution time of the unit tests and it can be:
- SHORT – less than a minute
- MEDIUM – less than five minutes
- LONG – longer than five minutes, relatively one hour
Eventually, these intervals can be customized. Yet, what we need to take into consideration is, that if the execution time exceeds the specified parameter, the ABAP Unit runner will throw an error.
In the end, to give a short illustration, a test class definition should have the following format:
CLASS ltc_my_test_class DEFINITION FOR TESTING
RISK LEVEL Critical|Dangerous|Harmless
DURATION Short|Medium|Long .
Worth to mention is, that the part of code in an application, that is unit tested, is usually called ”CUT” = Code Under Test.
If you are eager to find more about test classes, I suggest you to read the SAP Press E-book publication ”ABAP Unit: Writing and Executing Unit Tests”, written by James Wood and Joseph Rupert.
That being said, we have now arrived at the point of…
Creating a Test Method
A test method can be implemented exclusively in a test class. As a matter of fact, during a test run, test methods are called as individual tests and that means we will only have one instance of the test class per test method.
Notably here, the method that is going to be tested, actually the unit, is usually referred to as the ”Method Under Test” and it is part of the production code.
Test methods have no parameters but, similar with test classes, they have a ”FOR TESTING” addition at the end of the DEFINITION part. Another key point to remember is that a test method is declared in the PRIVATE SECTION of the class definition to underline that it can only be used in the context of its test class and not in other derived classes, as follows:
CLASS ltc_my_test_class DEFINITION FOR TESTING
test_method1 FOR TESTING.
test_method2 FOR TESTING.
The only situation where the test methods can be declared in the PROTECTED SECTION is when these methods are part of a superclass and are inherited by another test class.
The IMPLEMENTATION part of a test method should always tell us a story about what is going to be tested and this should also be reflected in the test method name. It usually follows the ”given – when – then” pattern that associates with the initialization, execution and result phases of the test case. We should think of a test method similar to a logical story in the following way:
”given -> a particular environment
This is an initialization part where our global class is instantiated.
”when -> we execute this CUT (code under test)
Here we normally call the method that is going to be tested together with the specified input values.
”then -> this outcome is expected
A test method has one or a few inputs and usually a single output.
Significantly, in the ”then” part of the test method, the outcome is validated through a comparison between the actual value that the method under test is returning and the real expected value. If the results do not match, the Unit test framework will throw an error. This comparison is made using one of the utility methods provided by the ABAP class ”CL_ABAP_UNIT_ASSERT”, which is called ”ASSERT_EQUALS”.
The most often used utility methods alongside with their SAP documentation are:
– ASSERT_EQUALS – ensures equality of two data objects
– ASSERT_BOUND / ASSERT_NOT_BOUND – ensures the validity / invalidity of the reference of a reference variable
– ASSERT_INITIAL / ASSERT_NOT_INITIAL – ensures that data object value is initial / is not initial
– ASSERT_TRUE / ASSERT_FALSE – ensures that a boolean equals ABAP_TRUE / ABAP_FALSE
– ASSERT_SUBRC – ensures a specific value of the return code
– FAIL – report unconditional assertion
– ABORT – abort test execution due to missing context.
They are also known as ”assertion methods” and their ultimate purpose is to pass messages to the ABAP Unit runner.
Naturally, it is not necessary for a test method to follow the above pattern, it is just a style of writing tests that helps for a better understanding of them. Instead, it is mandatory for it to include the logic inside these three parts.
Importantly to know about is that there are several special private methods used in test classes which are provided by the ABAP Unit framework. They implement a unique test behaviour and include the test objects and the connections needed for a proper execution. These are:
- SETUP( ) – instance method that is executed before each individual test or before each execution of a test method
The ”given” part of the tests can be implemented in the SETUP method, only if the test methods have the same code under test.
- TEARDOWN( ) – instance method that is executed after each individual test or after each execution of a test method
- CLASS_SETUP( ) – class method which is executed once before all tests of the class.
- CLASS_TEARDOWN( ) – class method which is executed once after every test of the class.
Actually, they are also called ”fixture methods” and have predefined names so that the ABAP Unit could recognize them at runtime. These methods are optional and should be used only if we need them.
There are already several software companies that have adopted the Unit Testing technique as part of their development process. Although it may be difficult to get used to it or to figure out what cases to cover, in a long-term perspective, unit tests lead to less maintenance efforts and costs. Unit tests are likely created by the developer, the reason for we call it ”white-box” testing, and it makes sense because the person who wrote the product code is the most qualified to know about what and how can be easily accessed and tested. Additionally, having a lot of tests for the small components of the application will demand much less debugging overall and that will also save our time. And time is very important for a developer, isn’t it?
Now, that you completed the theoretical part, you are ready to practice. Do not miss the second part of this series, which will show you how to build Unit Test Cases for the source code based on a practical example.
Sources of the images: https://open.sap.com