Technical Articles
SAP ABAP Unit test for Static dependency method with a “hack”
What?
ABAP Unit tests using OO Test Double Framework is a great tool for writing tests. However it has many limitations. One such is, it does not support static methods. classes which are marked STATIC (as mentioned in here ).
Why?
While I was writing test cases I came across this scenario. And after some research I did not find a clear answer, which motivated me to write this blog post.
Although it is not possible to create a double for a class method which is static, out of the box. We can still simulate this using a “hack” (p.s. I love hacks! 😎 ).
In this blog post I will cover an approach using which we can write tests for dependency static class method.
How?
Using Dynamic Method Call
Procedure Steps :
- Replace original method call to dynamic call
METHOD cut_method.
...
" Original Call
cl_static_class_name=>method_name
...
ENDMETHOD.
METHOD cut_method.
...
" Replace with
(vairable_name)=>method_name
...
ENDMETHOD.
- Set Class name
This can be done using one of the two possible approaches.Â
-
- Create Class attribute – Assign Initial value. Can be done in constructor.
METHOD constructor.
...
gv_class_attribue = 'CL_STATIC_CLASS_NAME'.
...
ENDMETHOD.
-
- Create Method variable – Assign value before call
METHOD cut_method.
...
lv_class_name_variable = 'CL_STATIC_CLASS_NAME'.
...
ENDMETHOD.
- Define and Implement local class with similar signature as dependency class
CLASS lcl_cut DEFINITION.
PUBLIC SECTION.
...
METHODS : cut_method ...
ENDCLASS.
CLASS lcl_cut IMPLEMENTATION.
METHOD cut_method.
...
ENDMETHOD.
ENDCLASS.
Note :
- Method name must be same as in dependency class with all the IMPORT, EXPORT and CHANGING variables.
- In the cut_method of newly created local class; based on some fixed values passed to it, both success and failure scenarios can be simulated.
- Modify Class name in Test Environment
Based on the approach used to Set Class name, Modify the Class name in Test Environment as shown below.
-
- For Class attribute
METHOD utm.
...
mo_cut->gv_static_class = 'lcl_cut'.
...
ENDMETHOD.
Note : Either the class attribute should be made public or local class should be made friends with CUT class.
-
- For Method variable
METHOD cut_method.
...
" Add test seam around variable assignment
TEST-SEAM set_static_class_name.
lv_class_name_variable = 'CL_STATIC_CLASS_NAME'.
END-TEST-SEAM.
...
ENDMETHOD.
--------------------------------------------------------------------------
METHOD utm.
...
TEST-INJECTION set_static_class_name.
lv_class_name_variable = 'LCL_CUT'.
END-TEST-INJECTION.
...
ENDMETHOD.
- Call CUT method
METHOD utm.
...
mo->cut_method ...
...
ENDMETHOD.
Conclusion
We learnt how to simulate double for a Static class method with a hack. I hope this would be helpful to many of those who are working on implementing ABAP Unit tests for existing written code or following TDD (Test Driven Development) for new code.
I am planning to create such short blog posts around ABAP Unit tests. Please do let me know your thoughts on this post, any suggestions/ feedback you have or any further questions on the post.
One better approach is from Matthew Billingham, which does not use Dynamic Method call.
It took me 5 minutes to understand what means "class marked STATIC" (from the SAP Library you mentioned: "Classes marked as FINAL, STATIC, or FOR TESTING"). In fact the ABAP word "STATIC" doesn't exist (or I failed in finding an explanation), it's just a weird way of talking about the static methods, which is the ABAP official name. So I would recommend that you don't use this weird term "static class", but use the official ABAP term "static method".
Sandra Rossi Yes, you are right indeed and I'm sad to hear about your discomfort. I have updated all the references in the blog post now. However not much can be done about SAP Development guide (here)😔.
Thank you for taking out time and the feedback. This would definitely help other readers.
I would also like to know about your thoughts on the approach I suggested in the blog post.
Thanks.
Concerning your solution, I wouldn't recommend it at all because test seams are to be avoided as far as possible because you add dummy code inside the productive code, and it reduces its legibility. In the case of static methods, I think they can be easily avoided by other injection possibilities.
Test Seam is one of the two possible ways in which this can be achieved. The other approach is having a class level attribute to store dependency class name (Right above the TEST-SEAM approach).
Technically other injection methods can be used. But in that case one might have to modify the dependency object (for Interface injection). However this is not always possible. The dependency class might not be always modifiable for various reasons.
My response here:Â