I will write here my experiences with a journey from SAP procedural programming, manual unit testing to SAP object oriented programming and test driven development (TDD).
When I was programming my first ABAP programs I was studying also SAP educs about object oriented programming and various other non-SAP books about object oriented programming (like for Java or C# language), design patterns, clean code, test automation, openSAP online free course about how to write testable code. Putting it all together I started to feel that advantages described in these books/sources have very good sense. I was reading also lot of pessimistic info on the internet, also from SAP community, that these things can not work in SAP well. In this information chaos I was still feeling that object oriented programming , automated tests , design patterns gives very good sense. So I started to create first local classes. This was bringing only little value to my coding, but I have improved in object oriented syntax , and also this pushed me more at least to better implement rules from books about clean code (although for clean code rules, the OOP is not inevitable). Then I created my first automated tests for some local classes, so I improved in syntax of a framework of SAP unit tests (at that time I did not use mocks, neither TDD). These improvements were important for my next steps but still there was a small difference in value between my old procedural programs and new procedural programs with local classes. I have decided to get more value from OOP and TDD so I decided to start to create global classes, although I had impression that I do not need them so much , I was not sure how to create them in such a way so that they are reusable. Later I have found out that there several other reasons why coding most of my code in global classes is inevitable.
My advise here to other developers would be start to create most of the code in global classes, and very little code (for things with very limited scope ) in the local classes.
I started to think that I need global interfaces and to mock the dependencies. To fully benefit from OOP and automated unit tests we have to start create also global interfaces. They are also very useful, inevitable for this coding style.
When I was creating first automated unit tests I thought that mocks are strange and spies, or adhoc test classes are sufficient for unit tests. Very quickly I discovered the real big power of mocks in unit tests. My advise concerning mocks would be that they are very good way how to handle dependencies, make the test more maintainable and they need to be used to realize bigger potential of unit tests. I can not imagine not to use mocks now.
When I started with abstract classes and polymorphism I discovered that I started to have a lot of repeating code in unit tests so I started to use abstract test classes to have repeating code for test classes in one place.
After I had better understanding of clean code rules, OOP, global classes, global interfaces, automated unit tests, mocks, abstract test classes then I fully realized how very important is to know them all together. Now I started to see that my code started to be more reusable, maintainable, stable, testable (these are some of important software quality criteria) – these things I would not be able to do on higher level with my procedural style of coding only . Especially when I started to code big programs I realized that I am able to keep them under control.
When I was able to do automated unit tests and OOP, I started to see that creating tests firsts has more advantages as creating them after I finish my program. I saw that creating tests first really (like described in books about TDD) helps me, leads me, to create real testable code, testable OOP. I started to think more in terms of interfaces. So this was leading me to understand that TDD is in fact inevitable, when I arrived in my journey here. Why I would code automated unit tests after finishing of the program if I would then spend more time with creating these tests and I would need to redesign my program to make it testable? If I create tests first, then I can avoid this. So for me TDD is not about the personal choice, but about saving time. Of course there are situations that are causing that I write tests after I update the program- for example if I discover that I missed some scenario and the program is already coded, or if I found the defect in the test…Most of my automated tests I prepare before the my program.
Concerning the maintenance of unit tests—I was kindly surprised how little time I spent with maintenance of the past unit tests. It is almost nothing…one time I decided to create an integration test instead of unit tests ( using this SAP unit test framework ), I was updating database in the unit test, I did not mock it, and this test failed one time, although I did not touched it. Other then that maintenance time is 0. This is one of the fear, that maintenance takes a lot of time. If all dependencies are isolated in the program, and the unit tests test only internal logic of the program, then currently I do not know why the unit tests should stop work (fail), if no other developer touched them. Also I was not sure if I will be able to understand, maintain myself after some time(months) my own tests. I was kindly surprised that it is quite easy.
I can confirm that advantages, benefits described(in books, or internet blogs...) by supporters of OOP and automated tests are real, valid. The purpose of this article is not to provide lists of all these benefits, they are well described elsewhere. One purpose of this article is also add courage to SAP developers who have a feeling that these technics really works, that they are on good way and if they keep their energy to improve their coding in this way, it has its good benefits.
When I started to use code coverage features in SAP unit frameworks , I have discovered that when I create test classes I have a tendency not to have high coverage because I have feelings that I will spend uselessly time for creating automated tests were there is a very low probability that there is some defect. It was not easy, it took me months, to decrease this temptation but after I have discovered that if I have low coverage then anyway it happened that there was some defect and with lower coverage I did not have so safe feeling, after I changed something/refactor/ in my program(class), that I did not break something. I discovered that creating automated unit tests for such part of code is more timesaving like to rely on that there is no defect. Also after few months , the creation of automated tests takes me less time, since the skills how to create them are increasing. Achieve 100% branch can be sometimes impossible for me, since test coverage tool reports untested branches also those ones which are not possible to go through, if my preceding code does not allow them. So I do not try fanatically pursue 100% coverage, although I would like to have it. I use mainly code coverage to check if I did not forgot to do some automatic test for it, it is a very good tool for this task.
The questions I have encountered on my way to TDD were, do I need for my SAP coding projects:
- clean code rules ?
- global classes and interfaces ?
- design patterns ?
- testable OOP style of code ?
- mocks ?
- higher code coverage with unit tests ?
- tests first(TDD) ?
My answer is clear "yes" for all of them.
Now I started to study behavior driven development, automating of acceptance tests. I have again same feeling that they are at least as important as automated unit tests. I am currently persuaded that teams with devops targets, who want to do real agile development, have no choice , but implement also automated acceptance tests, in addition to automatic unit tests (although some smaller amount of manual exploratory testing or frontend manual testing will most probably remain for long time…until the artificial intelligence will maybe replace most of the development, testing tasks).