In pursuit of making ABAP Unit Test less dependent and more independentĀ š, today I have decided to write on an interesting but less explored topic which is removing function module dependency in ABAP Unit Test using TDF. This is one of the less discussed topics in abap unit test double framework.After implementing some of them and in absence of as many resources as other topics, I have decided to share my experience with a sample example and put an overview in one place.
So while implementing ABAP Units, we may have come across scenarios where the Depended-On-Componen(DOC) is a function module.
So how do you mock that and remove that dependency.Letās see that with an example:
For the sake of demo I have created a sample function module which takes as input a document number and returns the number of items it has ( please donāt go by the use case as more focus is on the approachĀ š)
I have created a method in a sample class which uses the function module and has some processing logic based on the function moduleās output.
class ZCL_TEST_FM_DEMO definition
public
final
create public .
public section.
methods METHOD_UNDER_TEST
importing
!IV_EBELN type EBELN
exporting
!EV_ITM_COUNT type I .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_TEST_FM_DEMO IMPLEMENTATION.
METHOD METHOD_UNDER_TEST.
IF iv_ebeln IS NOT INITIAL.
CALL FUNCTION 'ZFM_DOC_GET_COUNT'
EXPORTING
ebeln = iv_ebeln
IMPORTING
count = ev_itm_count.
ENDIF.
"Further Processing Logic based on the item count
ENDMETHOD.
ENDCLASS.
Now in the test class I would make use of Test Double Framework specific to Function Modules to mock this FM and henceforth call the mocked instance instead of the productive one.
For this I have declared an environment variable which refers to the test double framework interface.
CLASS-DATA: fm_environment TYPE REF TO if_function_test_environment.
Then in Class-Setup method I create an instance and get the test double object.
fm_environment = cl_function_test_environment=>create( VALUE #( ( |ZFM_DOC_GET_COUNT| ) ) ).
DATA(fm_double) = fm_environment->get_double( |ZFM_DOC_GET_COUNT| ).
Itās time to set the input and output parameters.I create that using the create_input_configuration method and simultaneously the create_output_configuration method respectively.These configuration instances mock the actual import and export parameters of the function module.
DATA(input_data) = fm_double->create_input_configuration( )->set_importing_parameter( name = |ebeln| value = |5500000000| ).
DATA(output_data) = fm_double->create_output_configuration( )->set_exporting_parameter( name = |count| value = 2 ).
Finally I configure my test double to set the output when the same input is provided.In other words, I set the input and output expectations.
fm_double->configure_call( )->when( input_data )->then_set_output( output_data ).
Thatās it as far as mocking was concerned
Now as usual, in my unit test method I call the method under test as usual and create positive and negative scenarios.
METHOD determine_target_amount.
CONSTANTS: cv_ebeln_pos TYPE ebeln VALUE '5500000000',
cv_ebeln_neg TYPE ebeln VALUE '5500000001'.
"positive
f_cut->method_under_test(
EXPORTING
iv_ebeln = cv_ebeln_pos
IMPORTING
ev_itm_count = DATA(lv_itm_count) ).
cl_abap_unit_assert=>assert_equals(
act = lv_itm_count
exp = 2
msg = 'item count matched' ).
"negative
f_cut->method_under_test(
EXPORTING
iv_ebeln = cv_ebeln_neg
IMPORTING
ev_itm_count = lv_itm_count ).
cl_abap_unit_assert=>assert_initial(
act = lv_itm_count
msg = 'item count is initial' ).
ENDMETHOD.
What would happen is on the call of the function module, the test double framework generated function module will be called instead of the productive function module and you have the data in your control.This would make the test cases consistent across all environments and eliminate AUnit failures
Some additional points to remember:
- You can also set Tables and Changing parameters in the same way as exporting parameters
- Similarly, you can also set multiple importing, tables, changing and exporting parameters
- In the configure_call( ) method, you can also raise exceptions and ignore all input parameters and only set the output
Hope this resource was useful to some extent in bringing some relevant light on mocking Function Modules in ABAP Unit Test Classes.
Do post your comments, queries and suggestions if any on the same.
I am also available at LinkedIN atĀ https://www.linkedin.com/in/iheartsap/Ā for any queries.