by Vasiliy Kharitonov
Code without tests is bad code. It doesn’t matter how well-written it is; it doesn’t matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don’t know if our code is getting better or worse.
– Michael Feathers, Working Effectively with Legacy Code
Imagine, you could automatically test any change you (or your developer) made. And not just small isolated tests, you could immediately check if any of enhanced functionality is impacted. Sounds like magic but it is already an industry standard in other development environments. If someone makes a small logic mistake this magic immediately shows that something is wrong. With automatic unit testing effort for human testing is decreased, first time right is improved, and most important quality of the product is enhanced.
SAP recognized importance of automated testing as well and there is a test driven development for it. It might be not as advanced as something you would encounter in other environments, but it gets the job done.
Unfortunately, in order to use this functionality you will have to change your development approach and make some additional efforts for developers. First of all, you would need an improved technical architecture.
In all SAP projects I encountered in my career, the object model for developments usually looks in one of two ways.
The first one is the bad one. All of the enhanced functionality for some certain spot, all 2 thousands rows of ABAP code, is just packed into a single object, for example, into a single ABAP report.
The second one is better but still a bad one. For each development a new
separate object is created. E.g. classes
sub-objects (e.g. methods) are created for the main object to represent parts of
functionality that are repeated in multiple places.
What is required in the test driven development is an another approach to object
model. Technical architecture is missing in both usual approaches. To improve it
basically you should have separate objects representing separate types of
functionality. Logic for communicating with database should be a separate
object, for example, a class
Aside from database access object you would also need a separate object for all
custom interactions with users, including dialogs, selection screens, other
buttons and UI elements. For example, you could create a class
If you have some logic for integration with other systems, you should do the
same for it as well. For example, for custom integration with TM you could
create a class
This is essential for good test driven design. With good technical architecture, you will be able to replace these “integration” objects with some hardcoded test objects (SAP calls them test doubles). These test doubles should help produce some static calculated results and also keep your real database safe. You can use dependency lookup injection to replace objects of real classes with test doubles. It is a good practice to make both real class and test double class implementing the same custom interface. There are many reasons for it, but it is a topic for detailed article (part 2?).
Then your unit tests should be written by developers. Actually it is even better to first write unit tests and only then start your development. This way developers can use them not only for regression testing but during development process as well.
You can use ABAP Unit framework for writing tests. Good practice is to write some unit tests for each of your methods (or forms/function modules), doesn’t matter if it is private or public. E.g. if you have logic for destination bin filtering and sorting, you could write the following tests (simplified):
Then you will be able to run those tests for each new line of code, to check if everything works fine or not. Also, you will be able to use old tests for regression purposes, e.g. when you implement logic for bin dynamic separation and merging in the same enhancement spot.
The next step would be to run the tests automatically in the background and sent
some emails in case of errors. This can be easily accomplished with ABAP report
RS_AUCV_RUNNER running using a background job.