INTERFACE if_td_currency_converter PUBLIC .
EVENTS new_currency_code EXPORTING VALUE(currency_code) TYPE string.
METHODS convert
IMPORTING
amount TYPE i
source_currency TYPE string
target_currency TYPE string
RETURNING VALUE(result) TYPE i
RAISING cx_td_currency_exception.
METHODS convert_to_base_currency
IMPORTING
amount TYPE i
source_currency TYPE string
EXPORTING
base_currency TYPE string
base_curr_amount TYPE i.
ENDINTERFACE.
CLASS ltcl_abap_td_examples DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
METHODS:
create_double FOR TESTING RAISING cx_static_check,
ENDCLASS.
CLASS ltcl_abap_td_examples IMPLEMENTATION.
METHOD create_double.
DATA: lo_currency_converter_double TYPE REF TO if_td_currency_converter,
lo_expense_manager TYPE REF TO cl_td_expense_manager.
"create test double object
lo_currency_converter_double ?= cl_abap_testdouble=>create( 'if_td_currency_converter' ).
"injecting the test double into the object being tested
CREATE OBJECT lo_expense_manager EXPORTING currency_converter = lo_currency_converter_double.
ENDMETHOD.
ENDCLASS.
METHOD simple_configuration.
DATA: lo_currency_converter_double TYPE REF TO if_td_currency_converter,
lo_expense_manager TYPE REF TO cl_td_expense_manager,
lv_total_expense TYPE i.
"create test double object
lo_currency_converter_double ?= cl_abap_testdouble=>create( 'if_td_currency_converter' ).
"configuration for stubbing method 'convert':
"step 1: set the desired returning value for the method call
cl_abap_testdouble=>configure_call( lo_currency_converter_double )->returning( 80 ).
"step 2: specifying which method should get stubbed
lo_currency_converter_double->convert(
EXPORTING
amount = 100
source_currency = 'USD'
target_currency = 'EUR'
).
"injecting the test double into the object being tested
CREATE OBJECT lo_expense_manager EXPORTING currency_converter = lo_currency_converter_double.
"add one expense item
lo_expense_manager->add_expense_item(
EXPORTING
description = 'Line item 1'
currency_code = 'USD'
amount = '100'
).
"actual method call
lv_total_expense = lo_expense_manager->calculate_total_expense( currency_code = 'EUR' ).
"assertion
cl_abap_unit_assert=>assert_equals( exp = 80 act = lv_total_expense ).
ENDMETHOD.
METHOD configuration_variants.
DATA: lo_currency_converter_double TYPE REF TO if_td_currency_converter,
lo_expense_manager TYPE REF TO cl_td_expense_manager,
lv_total_expense TYPE i.
"create test double object
lo_currency_converter_double ?= cl_abap_testdouble=>create( 'if_td_currency_converter' ).
"eg1: configuration for exporting parameters
cl_abap_testdouble=>configure_call( lo_currency_converter_double )->set_parameter( name = 'base_currency' value = 'EUR'
)->set_parameter( name = 'base_curr_amount' value = 80 ).
lo_currency_converter_double->convert_to_base_currency(
EXPORTING
amount = 100
source_currency = 'USD'
).
"eg2: configuration ignoring one parameter. 55 gets returned if source currency = 'USD' , target currency = 'EUR' and any value for amount.
cl_abap_testdouble=>configure_call( lo_currency_converter_double )->returning( 55 )->ignore_parameter( 'amount' ).
lo_currency_converter_double->convert(
EXPORTING
amount = 0 "dummy value because amount is a non optional parameter
source_currency = 'USD'
target_currency = 'EUR'
).
"eg3: configuration ignoring all parameters. 55 gets returned for any input
cl_abap_testdouble=>configure_call( lo_currency_converter_double )->returning( 55 )->ignore_all_parameters( ).
lo_currency_converter_double->convert(
EXPORTING
amount = 0 "dummy value
source_currency = 'USD' "dummy value
target_currency = 'EUR' "dummy value
).
ENDMETHOD.
Please note that the configure_call method is used to configure the next method call statement on the test double. If you need to configure different methods of an interface, the configure_call method should be called for every method.
METHOD configuration_exception.
DATA: lo_currency_converter_double TYPE REF TO if_td_currency_converter,
lo_expense_manager TYPE REF TO cl_td_expense_manager,
lv_exp_total_expense TYPE i,
lo_exception TYPE REF TO cx_td_currency_exception.
FIELD-SYMBOLS: <lv_value> TYPE string.
"create test double object
lo_currency_converter_double ?= cl_abap_testdouble=>create( 'if_td_currency_converter' ).
"instantiate the exception object
CREATE OBJECT lo_exception.
"configuration for exception. The specified exception gets raised if amount = -1, source_currency = USD "and target_currency = 'EUR'
cl_abap_testdouble=>configure_call( lo_currency_converter_double )->raise_exception( lo_exception ).
lo_currency_converter_double->convert(
EXPORTING
amount = -1
source_currency = 'USD'
target_currency = 'EUR'
).
ENDMETHOD.
METHOD configuration_event.
DATA: lo_currency_converter_double TYPE REF TO if_td_currency_converter,
lo_expense_manager TYPE REF TO cl_td_expense_manager,
lv_total_expense TYPE i,
lv_exp_total_expense TYPE i,
lt_event_params TYPE abap_parmbind_tab,
ls_event_param TYPE abap_parmbind,
lo_handler TYPE REF TO lcl_event_handler.
FIELD-SYMBOLS: <lv_value> TYPE string.
"create test double object
lo_currency_converter_double ?= cl_abap_testdouble=>create( 'if_td_currency_converter' ).
"configuration for event. 'new_currency_code' event gets raised if the source_currency = INR
ls_event_param-name = 'currency_code'.
CREATE DATA ls_event_param-value TYPE string.
ASSIGN ls_event_param-value->* TO <lv_value>.
<lv_value> = 'INR'.
INSERT ls_event_param INTO TABLE lt_event_params.
cl_abap_testdouble=>configure_call( lo_currency_converter_double )->raise_event( name = 'new_currency_code' parameters = lt_event_params
)->ignore_parameter( 'target_currency'
)->ignore_parameter( 'amount' ).
lo_currency_converter_double->convert(
EXPORTING
amount = 0
source_currency = 'INR'
target_currency = ''
).
ENDMETHOD.
CLASS lcl_event_handler DEFINITION.
PUBLIC SECTION.
DATA: lv_new_currency_code TYPE string.
METHODS handle_new_currency_code FOR EVENT new_currency_code OF if_td_currency_converter IMPORTING currency_code.
ENDCLASS.
CLASS lcl_event_handler IMPLEMENTATION.
METHOD handle_new_currency_code.
lv_new_currency_code = currency_code.
ENDMETHOD.
ENDCLASS.
METHOD configuration_times.
DATA: lo_currency_converter_double TYPE REF TO if_td_currency_converter,
lo_expense_manager TYPE REF TO cl_td_expense_manager,
lv_total_expense TYPE i.
"create test double object
lo_currency_converter_double ?= cl_abap_testdouble=>create( 'if_td_currency_converter' ).
"configuration for returning 80 for 2 times
cl_abap_testdouble=>configure_call( lo_currency_converter_double )->returning( 80 )->times( 2 ).
lo_currency_converter_double->convert(
EXPORTING
amount = 100
source_currency = 'USD'
target_currency = 'EUR'
).
"configuration for returning 40 the next time
cl_abap_testdouble=>configure_call( lo_currency_converter_double )->returning( 40 ).
lo_currency_converter_double->convert(
EXPORTING
amount = 100
source_currency = 'USD'
target_currency = 'EUR'
).
ENDMETHOD.
METHOD verify_interaction.
DATA: lo_currency_converter_double TYPE REF TO if_td_currency_converter,
lo_expense_manager TYPE REF TO cl_td_expense_manager,
lv_total_expense TYPE i,
lv_exp_total_expense TYPE i VALUE 160.
"create test double object
lo_currency_converter_double ?= cl_abap_testdouble=>create( 'if_td_currency_converter' ).
"injecting the test double into the object being tested
CREATE OBJECT lo_expense_manager EXPORTING currency_converter = lo_currency_converter_double.
"add three expenses
lo_expense_manager->add_expense_item(
EXPORTING
description = 'Line item 1'
currency_code = 'USD'
amount = '100'
).
lo_expense_manager->add_expense_item(
EXPORTING
description = 'Line item 2'
currency_code = 'USD'
amount = '100'
).
lo_expense_manager->add_expense_item(
EXPORTING
description = 'Line item 3'
currency_code = 'INR'
amount = '100'
).
"configuration of expected interactions
cl_abap_testdouble=>configure_call( lo_currency_converter_double )->returning( 80 )->and_expect( )->is_called_times( 2 ).
lo_currency_converter_double->convert(
EXPORTING
amount = 100
source_currency = 'USD'
target_currency = 'EUR'
).
"actual method call
lv_total_expense = lo_expense_manager->calculate_total_expense( currency_code = 'EUR' ).
"assertion
cl_abap_unit_assert=>assert_equals( exp = lv_exp_total_expense act = lv_total_expense ).
"verify interactions on testdouble
cl_abap_testdouble=>verify_expectations( lo_currency_converter_double ).
ENDMETHOD.
CLASS lcl_my_matcher DEFINITION.
PUBLIC SECTION.
INTERFACES if_abap_testdouble_matcher.
ENDCLASS.
CLASS lcl_my_matcher IMPLEMENTATION.
METHOD if_abap_testdouble_matcher~matches.
DATA : lv_act_currency_code_data TYPE REF TO data,
lv_conf_currency_code_data TYPE REF TO data.
FIELD-SYMBOLS:
<lv_act_currency> TYPE string,
<lv_conf_currency> TYPE string.
IF method_name EQ 'CONVERT'.
lv_act_currency_code_data = actual_arguments->get_param_importing( 'source_currency' ).
lv_conf_currency_code_data = configured_arguments->get_param_importing( 'source_currency' ).
ASSIGN lv_act_currency_code_data->* TO <lv_act_currency>.
ASSIGN lv_conf_currency_code_data->* TO <lv_conf_currency>.
IF <lv_act_currency> IS ASSIGNED AND <lv_conf_currency> IS ASSIGNED.
IF <lv_act_currency> CP <lv_conf_currency>.
result = abap_true.
ENDIF.
ELSE.
result = abap_false.
ENDIF.
ENDIF.
ENDMETHOD.
ENDCLASS.
Using the custom matcher in a configuration
METHOD custom_matcher.
DATA: lo_currency_converter_double TYPE REF TO if_td_currency_converter,
lo_expense_manager TYPE REF TO cl_td_expense_manager,
lv_total_expense TYPE i,
lv_exp_total_expense TYPE i VALUE 160,
lo_matcher TYPE REF TO lcl_my_matcher.
"create test double object
lo_currency_converter_double ?= cl_abap_testdouble=>create( 'if_td_currency_converter' ).
"configuration
CREATE OBJECT lo_matcher.
cl_abap_testdouble=>configure_call( lo_currency_converter_double )->returning( 80 )->set_matcher( lo_matcher ).
lo_currency_converter_double->convert(
EXPORTING
amount = 100
source_currency = 'USD*'
target_currency = 'EUR'
).
"injecting the test double into the object being tested
CREATE OBJECT lo_expense_manager EXPORTING currency_converter = lo_currency_converter_double.
"add expenses with pattern
lo_expense_manager->add_expense_item(
EXPORTING
description = 'Line item 1'
currency_code = 'USDollar'
amount = '100'
).
lo_expense_manager->add_expense_item(
EXPORTING
description = 'Line item 2'
currency_code = 'USDLR'
amount = '100'
).
"actual method call
lv_total_expense = lo_expense_manager->calculate_total_expense( currency_code = 'EUR' ).
"assertion
cl_abap_unit_assert=>assert_equals( exp = lv_exp_total_expense act = lv_total_expense ).
ENDMETHOD.
CLASS lcl_my_answer IMPLEMENTATION.
METHOD if_abap_testdouble_answer~answer.
DATA : lv_src_currency_code_data TYPE REF TO data,
lv_tgt_currency_code_data TYPE REF TO data,
lv_amt_data TYPE REF TO data,
lt_event_params TYPE abap_parmbind_tab,
ls_event_param TYPE abap_parmbind.
FIELD-SYMBOLS:
<lv_src_currency_code> TYPE string,
<lv_tgt_currency_code> TYPE string,
<lv_amt> TYPE i,
<lv_value> TYPE string.
IF method_name EQ 'CONVERT'.
lv_src_currency_code_data = arguments->get_param_importing( 'source_currency' ).
lv_tgt_currency_code_data = arguments->get_param_importing( 'target_currency' ).
lv_amt_data = arguments->get_param_importing( 'amount' ).
ASSIGN lv_src_currency_code_data->* TO <lv_src_currency_code>.
ASSIGN lv_tgt_currency_code_data->* TO <lv_tgt_currency_code>.
ASSIGN lv_amt_data->* TO <lv_amt>.
IF <lv_src_currency_code> IS ASSIGNED AND <lv_tgt_currency_code> IS ASSIGNED AND <lv_amt> IS ASSIGNED.
IF <lv_src_currency_code> EQ 'INR' AND <lv_tgt_currency_code> EQ 'EUR'.
result->set_param_returning( <lv_amt> / 80 ).
ENDIF.
ENDIF.
ENDIF.
ENDMETHOD.
ENDCLASS.
Adding the custom answer implementation to a method call configuration
METHOD custom_answer.
DATA: lo_currency_converter_double TYPE REF TO if_td_currency_converter,
lo_expense_manager TYPE REF TO cl_td_expense_manager,
lv_total_expense TYPE i,
lv_exp_total_expense TYPE i VALUE 25,
lo_answer TYPE REF TO lcl_my_answer.
"create test double object
lo_currency_converter_double ?= cl_abap_testdouble=>create( 'if_td_currency_converter' ).
"instantiate answer object
CREATE OBJECT lo_answer.
"configuration
cl_abap_testdouble=>configure_call( lo_currency_converter_double )->ignore_parameter( 'amount' )->set_answer( lo_answer ).
lo_currency_converter_double->convert(
EXPORTING
amount = 0
source_currency = 'INR'
target_currency = 'EUR'
).
"injecting the test double into the object being tested
CREATE OBJECT lo_expense_manager EXPORTING currency_converter = lo_currency_converter_double.
"add the expense line items
lo_expense_manager->add_expense_item(
EXPORTING
description = 'Line item 1'
currency_code = 'INR'
amount = '80'
).
lo_expense_manager->add_expense_item(
EXPORTING
description = 'Line item 2'
currency_code = 'INR'
amount = '240'
).
lo_expense_manager->add_expense_item(
EXPORTING
description = 'Line item 3'
currency_code = 'INR'
amount = '800'
).
lo_expense_manager->add_expense_item(
EXPORTING
description = 'Line item 4'
currency_code = 'INR'
amount = '880'
).
"actual method call
lv_total_expense = lo_expense_manager->calculate_total_expense( currency_code = 'EUR' ).
"assertion
cl_abap_unit_assert=>assert_equals( exp = lv_exp_total_expense act = lv_total_expense ).
ENDMETHOD.
The framework currently supports the creation of test doubles for global interfaces. Support for non-final classes is already under discussions.
Have a look at the framework and feel free to give your feedback or ask questions in the comment section.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
3 | |
2 | |
2 | |
2 | |
2 | |
2 | |
2 | |
1 | |
1 | |
1 |