A-Unit Test for Function Modules using Test Double Framework

Estimated read time 16 min read

Hi All,

In this Blog I would like Exhibit a Scenario Where I will be working with AUNIT test for function module with test double framework.

Introduction 

A Test double removes dependencies on external objects like databases, services, classes, or function modules during unit testing. This ensures that tests focus on your code and remain stable and repeatable by controlling return values. 

 Requirement 

We need a Global variable to maintain our test environment for function module. Let us create a global variable GV_FUNC_ENVR with reference IF_FUNCTION_TEST_ENVIRONMENT. 

 CLASS-DATA: GV_FUNC_ENVR TYPE REF TO IF_FUNCTION_TEST_ENVIRONMENT. 

We configure the environment and assign the function modules that require test doubles. 

GV_FUNC_ENVR = CL_FUNCTION_TEST_ENVIRONMENT => CREATE (VALUE #(( ‘ ZPAW_FUNC_MODULE’))). 

Where ZPAW_FUNC_AUNIT_TEST is the function module and CL_FUNCTION_TEST_ENVIRONMENT is the standard class. 

We acquire the double we want to configure by specifying the function module’s name. 

DATA(LO_TESTDOUBLE_FUNCTION) = GV_FUNC_ENVR  

->GET_DOUBLE(‘ZPAW_FUNC_MODULE’). 

Next, we establish the input configuration, which defines a specific state. When all parameters match the defined criteria during the function module call, this configuration is activated. Correspondingly, an output configuration must be specified to assign values to the function module’s output parameters. 

 Configure Input parameter 

DATA(LO_INPUT_VALUE_CONFIG) = LO_TESTDOUBLE_FUNCTION->CREATE_INPUT_CONFIGURATION ( )->SET_IMPORTING_PARAMETER (NAME = ‘lv_carrier_id’ VALUE = ‘AA’). 

Configure Output parameter 

ADATA(LO_OUTPUT_VALUE_CONFIG) = LO_TESTDOUBLE_FUNCTION->CREATE_OUTPUT_CONFIGURATION ( )->SET_EXPORTING_PARAMETER (NAME = ‘lv_msg’ VALUE = ’Flight data found’). 

 

Now, we merge the two configurations. We configure the call so that when the input values match the defaults, the output is also set accordingly. 

Configure matching criteria 

LO_TESTDOUBLE_FUNCTION->CONFIGURE_CALL ( )-> WHEN(LO_INPUT_VALUE_CONFIG)->THEN_SET_OUTPUT (LO_OUTPUT_VALUE_CONFIG). 

Furthermore, beyond directly setting outputs, you can simulate alternative behaviors such as triggering classic exceptions, object-oriented exceptions, or providing immediate responses.  

This functionality mimics the behavior found in class test doubles. Additional information can be found within the interface IF_FTD_OUTPUT_CONFIG_SETTER. 

Function module under test.

 

FUNCTION zpaw_func_module
IMPORTING
VALUE(lv_carrier_id) TYPE /dmo/carrier_name
EXPORTING
VALUE(lv_msg) TYPE string
VALUE(lv_num_flights) TYPE i
VALUE(lv_total_seats) TYPE i.

DATA: lt_flights TYPE TABLE OF /dmo/flight.
” Check if input carrier ID is empty
IF lv_carrier_id IS INITIAL.
lv_msg = ‘Error: Carrier ID cannot be empty’.
ELSE.

” Fetch data from /dmo/flight based on carrier ID
SELECT * FROM /dmo/flight
WHERE carrier_id = _carrier_id
INTO TABLE _flights.

” Determine message based on the result set
lv_num_flights = lines( lt_flights ).

IF lv_num_flights > 0.
” Calculate total seats for the flights found
LOOP AT lt_flights INTO DATA(ls_flight).
lv_total_seats = lv_total_seats + ls_flight-seats_max.
ENDLOOP.

” Determine message based on total seats
IF lv_total_seats > 500.
lv_msg = ‘High Demand: Total seats exceed 500 for Carrier ID ‘.
ELSE.
lv_msg = ‘Success: flights found for Carrier ID ‘.
ENDIF.
ELSE.
lv_msg = ‘Info: No flights found for Carrier ID ‘.
ENDIF.
ENDIF.

ENDFUNCTION.

 

Complete code is mentioned below for AUNIT Test Class.

 

CLASS zcl_test_paw_func_aunit_test DEFINITION FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.

PRIVATE SECTION.
METHODS: test_func_module_success FOR TESTING,
test_func_module_no_data FOR TESTING,
test_func_module_high_demand FOR TESTING,
test_func_module_empty_carrid FOR TESTING,
test_func_module_flight_init FOR TESTING,
test_func_module_low_demand FOR TESTING.

CLASS-DATA: gv_func_envr TYPE REF TO if_function_test_environment.

CLASS-METHODS: class_setup,
class_teardown.
ENDCLASS.

CLASS zcl_test_paw_func_aunit_test IMPLEMENTATION.

METHOD class_setup.
gv_func_envr = cl_function_test_environment=>create( VALUE #( ( ‘ZPAW_FUNC_MODULE’ ) ) ).

*Mocking values for get details.
DATA(lo_testdouble_function) = gv_func_envr->get_double( ‘ZPAW_FUNC_MODULE’ ).

” Add 1st test double values
DATA(lo_input_value_config) = lo_testdouble_function->create_input_configuration(
)->set_importing_parameter( name = ‘lv_carrier_id’ value = ‘AA’ ).
DATA(lo_output_value_config) = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_msg’ value = ‘Flight data found’ ).
lo_testdouble_function->configure_call( )->when( lo_input_value_config )->then_set_output( lo_output_value_config ).

” Add 2nd test double values
lo_input_value_config = lo_testdouble_function->create_input_configuration(
)->set_importing_parameter( name = ‘lv_carrier_id’ value = ‘ZZ’ ).
lo_output_value_config = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_msg’ value = ‘Flight data not found’
).
lo_testdouble_function->configure_call( )->when( lo_input_value_config )->then_set_output( lo_output_value_config ).

” Add 3rd test double values
lo_input_value_config = lo_testdouble_function->create_input_configuration(
)->set_importing_parameter( name = ‘lv_carrier_id’ value = ‘ ‘ ).
lo_output_value_config = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_msg’ value = ‘Error: Carrier ID cannot be empty’ ).
lo_testdouble_function->configure_call( )->when( lo_input_value_config )->then_set_output( lo_output_value_config ).

” Add 4th test double values
lo_input_value_config = lo_testdouble_function->create_input_configuration(
)->set_importing_parameter( name = ‘lv_carrier_id’ value = ‘WW’ ).
lo_output_value_config = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_msg’ value = ‘Internal table is empty’
).
lo_testdouble_function->configure_call( )->when( lo_input_value_config )->then_set_output( lo_output_value_config ).

” Add 5th test double values
lo_input_value_config = lo_testdouble_function->create_input_configuration(
)->set_importing_parameter( name = ‘lv_carrier_id’ value = ‘LF’ ).
lo_output_value_config = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_msg’ value = ‘High Demand: Total seats exceed 500 for Carrier ID’ ).
lo_output_value_config = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_total_seats’ value = ‘800’ ).
lo_testdouble_function->configure_call( )->when( lo_input_value_config )->then_set_output( lo_output_value_config ).

” Add 6th test double values
lo_input_value_config = lo_testdouble_function->create_input_configuration(
)->set_importing_parameter( name = ‘lv_carrier_id’ value = ‘RH’ ).
lo_output_value_config = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_msg’ value = ‘Low Demand: Total seats less than 500’ ).
lo_output_value_config = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_total_seats’ value = ‘100’
).
lo_testdouble_function->configure_call( )->when( lo_input_value_config )->then_set_output( lo_output_value_config ).
ENDMETHOD.

METHOD class_teardown.
gv_func_envr->clear_doubles( ).
ENDMETHOD.

METHOD test_func_module_flight_init.
DATA: lv_carrier_id TYPE /dmo/carrier_name VALUE ‘WW’,
lv_msg TYPE string,
lv_num_flights TYPE i.
CALL FUNCTION ‘ZPAW_FUNC_MODULE’
EXPORTING
lv_carrier_id = lv_carrier_id
IMPORTING
lv_msg = lv_msg
lv_num_flights = lv_num_flights.
cl_abap_unit_assert=>assert_initial(
act = lv_num_flights ).
ENDMETHOD.

METHOD test_func_module_no_data.
DATA: lv_carrier_id TYPE /dmo/carrier_name VALUE ‘ZZ’,
lv_msg TYPE string.
CALL FUNCTION ‘ZPAW_FUNC_MODULE’
EXPORTING
lv_carrier_id = lv_carrier_id
IMPORTING
lv_msg = lv_msg.
cl_abap_unit_assert=>assert_equals(
act = lv_msg
exp = ‘Flight data not found’ ).
ENDMETHOD.

METHOD test_func_module_low_demand.
DATA: lv_carrier_id TYPE /dmo/carrier_name VALUE ‘RH’,
lv_msg TYPE string,
lv_total_seats TYPE i.
CALL FUNCTION ‘ZPAW_FUNC_MODULE’
EXPORTING
lv_carrier_id = lv_carrier_id
IMPORTING
lv_msg = lv_msg
lv_total_seats = lv_total_seats.
cl_abap_unit_assert=>assert_equals(
act = lv_total_seats
exp = ‘100’
msg = lv_msg ).
ENDMETHOD.

METHOD test_func_module_empty_carrid.
DATA: lv_carrier_id TYPE /dmo/carrier_name VALUE ‘ ‘,
lv_msg TYPE string.
CALL FUNCTION ‘ZPAW_FUNC_MODULE’
EXPORTING
lv_carrier_id = lv_carrier_id
IMPORTING
lv_msg = lv_msg.
cl_abap_unit_assert=>assert_not_initial(
act = lv_msg
msg = ‘Error: Carrier ID cannot be empty’ ).
ENDMETHOD.

METHOD test_func_module_success.
DATA: lv_carrier_id TYPE /dmo/carrier_name VALUE ‘AA’,
lv_msg TYPE string.
CALL FUNCTION ‘ZPAW_FUNC_MODULE’
EXPORTING
lv_carrier_id = lv_carrier_id
IMPORTING
lv_msg = lv_msg.
cl_abap_unit_assert=>assert_equals(
act = lv_msg
exp = ‘Flight data found’ ).
ENDMETHOD.

METHOD test_func_module_high_demand.
DATA: lv_carrier_id TYPE /dmo/carrier_name VALUE ‘LF’,
lv_msg TYPE string,
lv_total_seats TYPE i.
CALL FUNCTION ‘ZPAW_FUNC_MODULE’
EXPORTING
lv_carrier_id = lv_carrier_id
IMPORTING
lv_msg = lv_msg
lv_total_seats = lv_total_seats.
cl_abap_unit_assert=>assert_equals(
act = lv_total_seats
exp = ‘800’
msg = lv_msg ).
ENDMETHOD.
ENDCLASS.

 

Now Run as ABAP Aunit test with Coverage.  

Now Run as ABAP Aunit test with Trace. 

 

 

 

 

 

​ Hi All,In this Blog I would like Exhibit a Scenario Where I will be working with AUNIT test for function module with test double framework.Introduction A Test double removes dependencies on external objects like databases, services, classes, or function modules during unit testing. This ensures that tests focus on your code and remain stable and repeatable by controlling return values.  Requirement We need a Global variable to maintain our test environment for function module. Let us create a global variable GV_FUNC_ENVR with reference IF_FUNCTION_TEST_ENVIRONMENT.  CLASS-DATA: GV_FUNC_ENVR TYPE REF TO IF_FUNCTION_TEST_ENVIRONMENT. We configure the environment and assign the function modules that require test doubles. GV_FUNC_ENVR = CL_FUNCTION_TEST_ENVIRONMENT => CREATE (VALUE #(( ‘ ZPAW_FUNC_MODULE’))). Where ZPAW_FUNC_AUNIT_TEST is the function module and CL_FUNCTION_TEST_ENVIRONMENT is the standard class. We acquire the double we want to configure by specifying the function module’s name. DATA(LO_TESTDOUBLE_FUNCTION) = GV_FUNC_ENVR  ->GET_DOUBLE(‘ZPAW_FUNC_MODULE’). Next, we establish the input configuration, which defines a specific state. When all parameters match the defined criteria during the function module call, this configuration is activated. Correspondingly, an output configuration must be specified to assign values to the function module’s output parameters.  Configure Input parameter DATA(LO_INPUT_VALUE_CONFIG) = LO_TESTDOUBLE_FUNCTION->CREATE_INPUT_CONFIGURATION ( )->SET_IMPORTING_PARAMETER (NAME = ‘lv_carrier_id’ VALUE = ‘AA’). Configure Output parameter ADATA(LO_OUTPUT_VALUE_CONFIG) = LO_TESTDOUBLE_FUNCTION->CREATE_OUTPUT_CONFIGURATION ( )->SET_EXPORTING_PARAMETER (NAME = ‘lv_msg’ VALUE = ’Flight data found’).  Now, we merge the two configurations. We configure the call so that when the input values match the defaults, the output is also set accordingly. Configure matching criteria LO_TESTDOUBLE_FUNCTION->CONFIGURE_CALL ( )-> WHEN(LO_INPUT_VALUE_CONFIG)->THEN_SET_OUTPUT (LO_OUTPUT_VALUE_CONFIG). Furthermore, beyond directly setting outputs, you can simulate alternative behaviors such as triggering classic exceptions, object-oriented exceptions, or providing immediate responses.  This functionality mimics the behavior found in class test doubles. Additional information can be found within the interface IF_FTD_OUTPUT_CONFIG_SETTER. Function module under test. FUNCTION zpaw_func_module
IMPORTING
VALUE(lv_carrier_id) TYPE /dmo/carrier_name
EXPORTING
VALUE(lv_msg) TYPE string
VALUE(lv_num_flights) TYPE i
VALUE(lv_total_seats) TYPE i.

DATA: lt_flights TYPE TABLE OF /dmo/flight.
” Check if input carrier ID is empty
IF lv_carrier_id IS INITIAL.
lv_msg = ‘Error: Carrier ID cannot be empty’.
ELSE.

” Fetch data from /dmo/flight based on carrier ID
SELECT * FROM /dmo/flight
WHERE carrier_id = _carrier_id
INTO TABLE _flights.

” Determine message based on the result set
lv_num_flights = lines( lt_flights ).

IF lv_num_flights > 0.
” Calculate total seats for the flights found
LOOP AT lt_flights INTO DATA(ls_flight).
lv_total_seats = lv_total_seats + ls_flight-seats_max.
ENDLOOP.

” Determine message based on total seats
IF lv_total_seats > 500.
lv_msg = ‘High Demand: Total seats exceed 500 for Carrier ID ‘.
ELSE.
lv_msg = ‘Success: flights found for Carrier ID ‘.
ENDIF.
ELSE.
lv_msg = ‘Info: No flights found for Carrier ID ‘.
ENDIF.
ENDIF.

ENDFUNCTION. Complete code is mentioned below for AUNIT Test Class. CLASS zcl_test_paw_func_aunit_test DEFINITION FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.

PRIVATE SECTION.
METHODS: test_func_module_success FOR TESTING,
test_func_module_no_data FOR TESTING,
test_func_module_high_demand FOR TESTING,
test_func_module_empty_carrid FOR TESTING,
test_func_module_flight_init FOR TESTING,
test_func_module_low_demand FOR TESTING.

CLASS-DATA: gv_func_envr TYPE REF TO if_function_test_environment.

CLASS-METHODS: class_setup,
class_teardown.
ENDCLASS.

CLASS zcl_test_paw_func_aunit_test IMPLEMENTATION.

METHOD class_setup.
gv_func_envr = cl_function_test_environment=>create( VALUE #( ( ‘ZPAW_FUNC_MODULE’ ) ) ).

*Mocking values for get details.
DATA(lo_testdouble_function) = gv_func_envr->get_double( ‘ZPAW_FUNC_MODULE’ ).

” Add 1st test double values
DATA(lo_input_value_config) = lo_testdouble_function->create_input_configuration(
)->set_importing_parameter( name = ‘lv_carrier_id’ value = ‘AA’ ).
DATA(lo_output_value_config) = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_msg’ value = ‘Flight data found’ ).
lo_testdouble_function->configure_call( )->when( lo_input_value_config )->then_set_output( lo_output_value_config ).

” Add 2nd test double values
lo_input_value_config = lo_testdouble_function->create_input_configuration(
)->set_importing_parameter( name = ‘lv_carrier_id’ value = ‘ZZ’ ).
lo_output_value_config = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_msg’ value = ‘Flight data not found’
).
lo_testdouble_function->configure_call( )->when( lo_input_value_config )->then_set_output( lo_output_value_config ).

” Add 3rd test double values
lo_input_value_config = lo_testdouble_function->create_input_configuration(
)->set_importing_parameter( name = ‘lv_carrier_id’ value = ‘ ‘ ).
lo_output_value_config = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_msg’ value = ‘Error: Carrier ID cannot be empty’ ).
lo_testdouble_function->configure_call( )->when( lo_input_value_config )->then_set_output( lo_output_value_config ).

” Add 4th test double values
lo_input_value_config = lo_testdouble_function->create_input_configuration(
)->set_importing_parameter( name = ‘lv_carrier_id’ value = ‘WW’ ).
lo_output_value_config = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_msg’ value = ‘Internal table is empty’
).
lo_testdouble_function->configure_call( )->when( lo_input_value_config )->then_set_output( lo_output_value_config ).

” Add 5th test double values
lo_input_value_config = lo_testdouble_function->create_input_configuration(
)->set_importing_parameter( name = ‘lv_carrier_id’ value = ‘LF’ ).
lo_output_value_config = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_msg’ value = ‘High Demand: Total seats exceed 500 for Carrier ID’ ).
lo_output_value_config = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_total_seats’ value = ‘800’ ).
lo_testdouble_function->configure_call( )->when( lo_input_value_config )->then_set_output( lo_output_value_config ).

” Add 6th test double values
lo_input_value_config = lo_testdouble_function->create_input_configuration(
)->set_importing_parameter( name = ‘lv_carrier_id’ value = ‘RH’ ).
lo_output_value_config = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_msg’ value = ‘Low Demand: Total seats less than 500’ ).
lo_output_value_config = lo_testdouble_function->create_output_configuration(
)->set_exporting_parameter( name = ‘lv_total_seats’ value = ‘100’
).
lo_testdouble_function->configure_call( )->when( lo_input_value_config )->then_set_output( lo_output_value_config ).
ENDMETHOD.

METHOD class_teardown.
gv_func_envr->clear_doubles( ).
ENDMETHOD.

METHOD test_func_module_flight_init.
DATA: lv_carrier_id TYPE /dmo/carrier_name VALUE ‘WW’,
lv_msg TYPE string,
lv_num_flights TYPE i.
CALL FUNCTION ‘ZPAW_FUNC_MODULE’
EXPORTING
lv_carrier_id = lv_carrier_id
IMPORTING
lv_msg = lv_msg
lv_num_flights = lv_num_flights.
cl_abap_unit_assert=>assert_initial(
act = lv_num_flights ).
ENDMETHOD.

METHOD test_func_module_no_data.
DATA: lv_carrier_id TYPE /dmo/carrier_name VALUE ‘ZZ’,
lv_msg TYPE string.
CALL FUNCTION ‘ZPAW_FUNC_MODULE’
EXPORTING
lv_carrier_id = lv_carrier_id
IMPORTING
lv_msg = lv_msg.
cl_abap_unit_assert=>assert_equals(
act = lv_msg
exp = ‘Flight data not found’ ).
ENDMETHOD.

METHOD test_func_module_low_demand.
DATA: lv_carrier_id TYPE /dmo/carrier_name VALUE ‘RH’,
lv_msg TYPE string,
lv_total_seats TYPE i.
CALL FUNCTION ‘ZPAW_FUNC_MODULE’
EXPORTING
lv_carrier_id = lv_carrier_id
IMPORTING
lv_msg = lv_msg
lv_total_seats = lv_total_seats.
cl_abap_unit_assert=>assert_equals(
act = lv_total_seats
exp = ‘100’
msg = lv_msg ).
ENDMETHOD.

METHOD test_func_module_empty_carrid.
DATA: lv_carrier_id TYPE /dmo/carrier_name VALUE ‘ ‘,
lv_msg TYPE string.
CALL FUNCTION ‘ZPAW_FUNC_MODULE’
EXPORTING
lv_carrier_id = lv_carrier_id
IMPORTING
lv_msg = lv_msg.
cl_abap_unit_assert=>assert_not_initial(
act = lv_msg
msg = ‘Error: Carrier ID cannot be empty’ ).
ENDMETHOD.

METHOD test_func_module_success.
DATA: lv_carrier_id TYPE /dmo/carrier_name VALUE ‘AA’,
lv_msg TYPE string.
CALL FUNCTION ‘ZPAW_FUNC_MODULE’
EXPORTING
lv_carrier_id = lv_carrier_id
IMPORTING
lv_msg = lv_msg.
cl_abap_unit_assert=>assert_equals(
act = lv_msg
exp = ‘Flight data found’ ).
ENDMETHOD.

METHOD test_func_module_high_demand.
DATA: lv_carrier_id TYPE /dmo/carrier_name VALUE ‘LF’,
lv_msg TYPE string,
lv_total_seats TYPE i.
CALL FUNCTION ‘ZPAW_FUNC_MODULE’
EXPORTING
lv_carrier_id = lv_carrier_id
IMPORTING
lv_msg = lv_msg
lv_total_seats = lv_total_seats.
cl_abap_unit_assert=>assert_equals(
act = lv_total_seats
exp = ‘800’
msg = lv_msg ).
ENDMETHOD.
ENDCLASS.  Now Run as ABAP Aunit test with Coverage.  Now Run as ABAP Aunit test with Trace.        Read More Application Development Blog Posts articles 

#SAP

You May Also Like

More From Author

+ There are no comments

Add yours