Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
nabheetscn
Active Contributor
All Blogs in the series
















1. ABAP Unit Test Week 1
2. ABAP Unit Test in Odata
3. ABAP Unit Test TDD Implementation
4. ABAP Unit  Test Meets Legacy Code.


 

Finally done with week 3  of Open SAP course where we saw how to add ABAP unit testing in existing legacy code. We already had a great feedback back about Week 3 in this blog by bfeeb8ed7fa64a7d95efc21f74a8c135. I thought of applying it in one of near to actual scenario to see how it looks. I have few observations on pair programming which hopefully I will share via separate blog.

Background of Existing Report


This is a 5+ years old report written in a procedural way with all the global data declarations etc. What it does is as follow

  • Check for a user whose name begins with XXX* and valid to date is greater than current date

  • If valid user check number of days between user creation and valid to date, if greater than 60 it modifies the validity date to creation date + 60 days


Awesome Features of current legacy report:)

  • No selection screen

  • 60 days is hardcoded.

  • Username pattern is hard coded


Sample code to change the validity
*   Difference between from and to days
CALL FUNCTION 'HR_HK_DIFF_BT_2_DATES'
EXPORTING
date1 = dateto
date2 = datefrom
output_format = '02' " Out put in days
IMPORTING
days = dayscount
EXCEPTIONS
invalid_dates_specified = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.

IF dayscount GT c_limit.
newdate = gw_logond-gltgv + 60 .
MOVE-CORRESPONDING gw_logond TO datenew.
datenew-gltgb = newdate.

* Change the Valid Through date , in case of days of validity is more than 60
CALL FUNCTION 'BAPI_USER_CHANGE'
EXPORTING
username = usr02-bname
logondata = datenew
logondatax = change
TABLES
return = return.
IF sy-subrc IS INITIAL.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'.
ENDIF.
ENDIF.
ENDIF.

Enhancement Needed.


This concept now needs to be extended to another set of users whose name begin with YYY* and whose validity shall be for 45 days. Easiest and the worst solution will be to add mine YYY* user id and hardcode another 45 days with IF and ELSE stuff. But I thought of why don’t we implement it via unit test class, it will make every life easier, testable and flexible.

Implementing Unit testing in Legacy code


The most important place in the code is where it decides whether the user needs to be modified or not that is where all action will happen. So started by creating our local test class with method ABC with parameters difference between number of days and username.

So started by creating local unit test class LTC_USERVALIDITY with method test method USER_DAYS for testing. This method will pass Username, Number of days between creation and valid to date and creation date to determine whether a user needs to be updated or not. If update is required Y flag is returned along with calculated date.
CLASS ltc_uservalidity DEFINITION FOR TESTING
RISK LEVEL HARMLESS
DURATION SHORT.
PRIVATE SECTION.
DATA: m_cut TYPE REF TO lcl_uservalidity.
METHODS setup.
METHODS user_days FOR TESTING RAISING cx_static_check.

ENDCLASS.
CLASS ltc_uservalidity IMPLEMENTATION.
METHOD setup.
m_cut = NEW lcl_uservalidity( ).
ENDMETHOD.
METHOD user_days.

" 60 Days test all possible combinations for XXX
m_cut->check_userendate_upd_needed( EXPORTING
userid = 'XXX123'
days = 60
startdate ='20180130'
IMPORTING r_result = DATA(checkvalue) r_newenddate = DATA(enddate) ).
cl_abap_unit_assert=>assert_equals( act = checkvalue
exp = 'Y' ).
m_cut->check_userendate_upd_needed( EXPORTING
userid = 'XXX123'
days = 59
startdate ='20180131'
IMPORTING r_result = checkvalue r_newenddate = enddate ).
cl_abap_unit_assert=>assert_equals( act = checkvalue
exp = 'N' ).
m_cut->check_userendate_upd_needed( EXPORTING
userid = 'XXX123'
days = 61
startdate ='20180129'
IMPORTING r_result = checkvalue r_newenddate = enddate ).
cl_abap_unit_assert=>assert_equals( act = checkvalue
exp = 'Y' ).
m_cut->check_userendate_upd_needed( EXPORTING
userid = 'XTZ123'
days = 59
startdate ='20180131'
IMPORTING r_result = checkvalue r_newenddate = enddate ).
cl_abap_unit_assert=>assert_equals( act = checkvalue
exp = 'N' ).
" 45 Days test all possible combinations for YYY
m_cut->check_userendate_upd_needed( EXPORTING
userid = 'YYY123'
days = 45
startdate ='20180130'
IMPORTING r_result = checkvalue r_newenddate = enddate ).
cl_abap_unit_assert=>assert_equals( act = checkvalue
exp = 'Y' ).
m_cut->check_userendate_upd_needed( EXPORTING
userid = 'YYY123'
days = 44
startdate ='20180130'
IMPORTING r_result = checkvalue r_newenddate = enddate ).
cl_abap_unit_assert=>assert_equals( act = checkvalue
exp = 'N' ).
m_cut->check_userendate_upd_needed( EXPORTING
userid = 'YYY123'
days = 48
startdate ='20180130'
IMPORTING r_result = checkvalue r_newenddate = enddate ).
cl_abap_unit_assert=>assert_equals( act = checkvalue
exp = 'Y' ).
m_cut->check_userendate_upd_needed( EXPORTING
userid = 'XTZ123'
days = 49
startdate ='20180130'
IMPORTING r_result = checkvalue r_newenddate = enddate ).
cl_abap_unit_assert=>assert_equals( act = checkvalue
exp = 'N' ).

ENDMETHOD.

ENDCLASS.

A custom table for mapping username with number of days was also created.



Then defined the actual method CHECK_USERENDATE_UPD_NEEDED to check from custom table whether a user needs to be updated or not.
CLASS lcl_uservalidity DEFINITION
FINAL
CREATE PUBLIC .

PUBLIC SECTION.

DATA: username TYPE bname,
days TYPE i,
userdays TYPE STANDARD TABLE OF zuserdays.

METHODS constructor.
METHODS check_userendate_upd_needed
IMPORTING
userid TYPE xubname
days TYPE pea_scrdd
startdate TYPE sy-datum
EXPORTING
r_result TYPE string
r_newenddate TYPE sy-datum .
PROTECTED SECTION.
PRIVATE SECTION.

ENDCLASS.

CLASS lcl_uservalidity IMPLEMENTATION.

METHOD constructor.
" Master data for days for user name
SELECT * FROM zuserdays INTO TABLE userdays.
ENDMETHOD.


METHOD check_userendate_upd_needed.
DATA:ls_userdays TYPE zuserdays,
uname TYPE bname.
uname = userid+0(3).
READ TABLE userdays INTO ls_userdays WITH KEY username = uname .
IF sy-subrc EQ 0.
IF ls_userdays-zdays > days.
r_result = 'N'.
ELSE.
r_result = 'Y'.
r_newenddate = startdate + ls_userdays-zdays.
ENDIF.
ELSE.
r_result = 'N'.
ENDIF.
ENDMETHOD.

ENDCLASS.

Added the selection screen parameter for user type



Finally removed the hardcoded part added our user date extender determiner plugin:)
*          Hardcoded part commented added our plugin which determine if date needs to
* to be changed or not if yes then calculate also.

* IF gv_count GT c_limit.
* gv_newdate = gw_logond-gltgv + 60 .

uservalidity->check_userendate_upd_needed( EXPORTING
userid = gw_bname-bname
days = gv_count
startdate = gv_fromdate
IMPORTING r_result = DATA(checkvalue) r_newenddate = DATA(enddate) ).
IF checkvalue = 'Y'.
MOVE-CORRESPONDING gw_logond TO gw_newdate.
gw_newdate-gltgb = enddate.
* gw_newdate-gltgb = gV_newdate.

It worked flawlessly.


Benefits



  • Clearly any change in report done does not matter by whom he/she shall be able to validate that at least this part of the code is not impacted by his/her change.

  • Once the ABAP unit framework is set normally people tend to follow it, so hopefully this program will eventually become better with each iteration.

  • I came to know about the concept of Test Seam introduced in latest ABAP version, for more detail read this blog by klaus.ziegler


 

Challenges or Open Points



  • One of the important thing which I am still thinking is how do I add flexibility to my code not only in terms of username and days, but also if a new criteria needs to be added later for example user type? Some kind of a similar abstraction concept needs to be bring in, will share as soon as I have got it implemented.

  • Reluctance to write so much code for just another if and else


 

What next from here?



  • Some thing about Test Seam

  • ABAP Test Double framework.


 

Feel free to provide your feedback open to all ears.
15 Comments