Become Function Module Independent ft. ABAP Units
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.