Update content
This commit is contained in:
@@ -136,7 +136,7 @@
|
|||||||
- are optional for all table categories.
|
- are optional for all table categories.
|
||||||
- can be unique/non-unique sorted keys or unique hash keys.
|
- can be unique/non-unique sorted keys or unique hash keys.
|
||||||
- have a self-defined name. An alias name can also be specified.
|
- have a self-defined name. An alias name can also be specified.
|
||||||
- A secondary table index is created internally for each sorted secondary key. This allows index access to hashed tables via the secondary table key is possible. In this case, `sy-tabix` is set.
|
- A secondary table index is created internally for each sorted secondary key. This allows index access to hashed tables via the secondary table key. In this case, `sy-tabix` is set.
|
||||||
- When accessing internal tables using the secondary table key, the key name (or the alias if specified) must be specified. They are not selected automatically. If no secondary key is specified in a processing statement, the primary key or primary table index is always used. If you want to make use of this key in ABAP statements, for example, `READ`, `LOOP AT` or `MODIFY` statements, you must specify the key explicitly using the appropriate additions, for example, `WITH ... KEY ... COMPONENTS` or `USING KEY`.
|
- When accessing internal tables using the secondary table key, the key name (or the alias if specified) must be specified. They are not selected automatically. If no secondary key is specified in a processing statement, the primary key or primary table index is always used. If you want to make use of this key in ABAP statements, for example, `READ`, `LOOP AT` or `MODIFY` statements, you must specify the key explicitly using the appropriate additions, for example, `WITH ... KEY ... COMPONENTS` or `USING KEY`.
|
||||||
- Use cases:
|
- Use cases:
|
||||||
- To improve read performance.
|
- To improve read performance.
|
||||||
@@ -1416,7 +1416,7 @@ the content are removed, but the memory space initially requested remains
|
|||||||
allocated. If the table is filled again later, the memory space is still
|
allocated. If the table is filled again later, the memory space is still
|
||||||
available, which is a performance advantag over
|
available, which is a performance advantag over
|
||||||
clearing an internal table with `FREE`. Such a statement also
|
clearing an internal table with `FREE`. Such a statement also
|
||||||
deleted the table content, but it also releases the memory
|
deletes the table content, but it also releases the memory
|
||||||
space.
|
space.
|
||||||
|
|
||||||
``` abap
|
``` abap
|
||||||
|
|||||||
@@ -422,93 +422,12 @@ There are multiple ways to implement test doubles manually:
|
|||||||
**Injecting the test doubles**
|
**Injecting the test doubles**
|
||||||
|
|
||||||
As described [here](https://help.sap.com/docs/ABAP_PLATFORM_NEW/c238d694b825421f940829321ffa326a/04a2d0fc9cd940db8aedf3fa29e5f07e.html?locale=en-US), there are multiple techniques for injecting test doubles to ensure that the test doubles are used during the test run.
|
As described [here](https://help.sap.com/docs/ABAP_PLATFORM_NEW/c238d694b825421f940829321ffa326a/04a2d0fc9cd940db8aedf3fa29e5f07e.html?locale=en-US), there are multiple techniques for injecting test doubles to ensure that the test doubles are used during the test run.
|
||||||
To name two of them:
|
|
||||||
- Constructor injection
|
|
||||||
- Back door injection
|
|
||||||
|
|
||||||
|
Among them, there are the following. They are demonstrated in the executable example. Check the code and comments in the [global class](./src/zcl_demo_abap_unit_test.clas.abap) and [test include](./src/zcl_demo_abap_unit_test.clas.testclasses.abap) of the example.
|
||||||
*Constructor injection*
|
- Constructor injection: The test double is passed as a parameter to the instance constructor `constructor` of the class under test.
|
||||||
- This injection mechanism means that the test double is passed as a parameter to the instance constructor `constructor` of the class under test.
|
- Setter injection: The test double is passed as a parameter to a setter method.
|
||||||
- `constructor` declaration:
|
- Parameter injection: The test double is passed as a parameter to the tested method (i.e. an optional importing parameter) in the class under test.
|
||||||
- Has an optional importing parameter for the DOC.
|
- Back door injection: A *back door* is created to inject a test double into the class under test. This *back door* is implemented by granting [friendship](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenfriend_glosry.htm) to the test class. This makes internal attributes of the class under test accessible from the test class.
|
||||||
- The parameter is typed with reference to the test double, i.e. an object of the test double is passed.
|
|
||||||
- `constructor` implementation:
|
|
||||||
- In the example beloew, it is assumed that an interface exists for the DOC, and a test double has been implemented that implements that interface.
|
|
||||||
- A reference variable with a type reference to the interface is declared in the declaration part of the class under test.
|
|
||||||
- When the unit test is executed, an object of the test double is created in the test method. This object is then passed to the `constructor`. A check is implemented to determine if the reference variable is bound. During the unit test execution, it is indeed bound, and the test double is injected. If the unit test is not run and the class is executed, an object of the *regular data provider* (e.g. a class that implements the interface for production use) is created. Therefore, it is ensured that the test double is only used in the context of a unit test run.
|
|
||||||
|
|
||||||
Such a constructor injection might look like this.
|
|
||||||
|
|
||||||
``` abap
|
|
||||||
"See the executable example for the complete picture.
|
|
||||||
"The code in this snippet refers to the production code.
|
|
||||||
...
|
|
||||||
"Class declaration part
|
|
||||||
DATA ref_data_provider TYPE REF TO if_data,
|
|
||||||
|
|
||||||
"Optional parameter for passing an object of the test touble
|
|
||||||
METHODS constructor
|
|
||||||
IMPORTING iref_data_prov TYPE REF TO tld_test_double OPTIONAL.
|
|
||||||
|
|
||||||
....
|
|
||||||
|
|
||||||
"Class implementation part
|
|
||||||
METHOD constructor.
|
|
||||||
"If the object of the test touble is not passed, an object is created for the actual data provider
|
|
||||||
|
|
||||||
IF iref_data_prov IS BOUND.
|
|
||||||
|
|
||||||
"Note: The parameter is only bound when running in ABAP unit test
|
|
||||||
ref_data_provider = iref_data_prov.
|
|
||||||
|
|
||||||
ELSE.
|
|
||||||
|
|
||||||
ref_data_provider = NEW cl_data_provider( ).
|
|
||||||
|
|
||||||
ENDIF.
|
|
||||||
ENDMETHOD.
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
*Back door injection*
|
|
||||||
- This injection mechanism means that a *back door* is created to inject a test double into the class under test.
|
|
||||||
- This *back door* is implemented by granting [friendship](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenfriend_glosry.htm) to the test class. This makes internal attributes of the class under test accessible from the test class.
|
|
||||||
- The back door injection enters the picture when internal attributes of the class under test are changed during the test run. That is, in the production code, you have declared a reference variable with a type reference to the data provider in the private section, for example.
|
|
||||||
- Note: Similar to above, in the example below, it is assumed that there is an interface for the DOC and that a test double has been implemented that implements that interface.
|
|
||||||
- When the unit test is executed, the private attribute of the class under test is changed, and an object of the test double is injected.
|
|
||||||
|
|
||||||
|
|
||||||
``` abap
|
|
||||||
"See the executable example for the complete picture.
|
|
||||||
"The code in this snippet refers to the test class.
|
|
||||||
|
|
||||||
"Test class declaration part
|
|
||||||
...
|
|
||||||
|
|
||||||
"class under test
|
|
||||||
DATA ref_cut TYPE REF TO cl_class_under_test.
|
|
||||||
|
|
||||||
"if_data_provider: interface with which local test data are created
|
|
||||||
"by implementing an interface method
|
|
||||||
DATA ref_data_prov TYPE REF TO if_data_provider.
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
"Implementation of the setup method in the test class
|
|
||||||
METHOD setup.
|
|
||||||
|
|
||||||
ref_cut = NEW #( ).
|
|
||||||
|
|
||||||
"Assumption: The local test double ltd_test_double implements the interface if_data_provider
|
|
||||||
ref_data_prov = new ltd_test_double( ).
|
|
||||||
|
|
||||||
"Back door injection
|
|
||||||
"The reference variable declared in the class under test is assigned an object
|
|
||||||
"of the test double. In the class under test, the reference variable is defined
|
|
||||||
"with type TYPE REF TO if_data_provider.
|
|
||||||
ref_cut->ref_var_defined_in_cut = ref_data_prov.
|
|
||||||
ENDMETHOD.
|
|
||||||
```
|
|
||||||
|
|
||||||
<p align="right">(<a href="#top">back to top</a>)</p>
|
<p align="right">(<a href="#top">back to top</a>)</p>
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,13 @@ CLASS zcl_demo_abap_unit_test DEFINITION
|
|||||||
|
|
||||||
"Reference variable for constructor injection
|
"Reference variable for constructor injection
|
||||||
"In the example, the type refers to a global interface.
|
"In the example, the type refers to a global interface.
|
||||||
data_provider_global_itf TYPE REF TO zdemo_abap_get_data_itf.
|
data_provider_global_itf TYPE REF TO zdemo_abap_get_data_itf,
|
||||||
|
|
||||||
|
"For demonstrating setter injection
|
||||||
|
data_provider_setter_inj TYPE REF TO zdemo_abap_get_data_itf,
|
||||||
|
|
||||||
|
"For demonstrating parameter injection
|
||||||
|
data_provider_param_inj TYPE REF TO zdemo_abap_get_data_itf..
|
||||||
|
|
||||||
METHODS:
|
METHODS:
|
||||||
"Calculates the sum of two numbers
|
"Calculates the sum of two numbers
|
||||||
@@ -122,6 +128,9 @@ CLASS zcl_demo_abap_unit_test DEFINITION
|
|||||||
"but serve different demonstration purposes for the ABAP unit tests in the example.
|
"but serve different demonstration purposes for the ABAP unit tests in the example.
|
||||||
"The method implementations involve a depended-on component (DOC). In this case,
|
"The method implementations involve a depended-on component (DOC). In this case,
|
||||||
"it is a database access.
|
"it is a database access.
|
||||||
|
"The methods are intentionally implemented in a similar way. Therefore, almost
|
||||||
|
"all of the following methods will display the same output in the console when the
|
||||||
|
"class is executed using F9.
|
||||||
|
|
||||||
"Method to demonstrate test double injection using inheritance and method redefinition
|
"Method to demonstrate test double injection using inheritance and method redefinition
|
||||||
get_occ_rate_using_meth IMPORTING carrier_id TYPE zdemo_abap_fli-carrid
|
get_occ_rate_using_meth IMPORTING carrier_id TYPE zdemo_abap_fli-carrid
|
||||||
@@ -139,6 +148,19 @@ CLASS zcl_demo_abap_unit_test DEFINITION
|
|||||||
|
|
||||||
"Method to demonstrate test double injection using constructor injection and a global interface
|
"Method to demonstrate test double injection using constructor injection and a global interface
|
||||||
get_occ_rate_global_itf IMPORTING carrier_id TYPE zdemo_abap_fli-carrid
|
get_occ_rate_global_itf IMPORTING carrier_id TYPE zdemo_abap_fli-carrid
|
||||||
|
RETURNING VALUE(occupancy_rate) TYPE occ_rate,
|
||||||
|
|
||||||
|
"Method to demonstrate test double injection using setter injection and a global interface
|
||||||
|
get_occ_rate_setter_inj IMPORTING carrier_id TYPE zdemo_abap_fli-carrid
|
||||||
|
RETURNING VALUE(occupancy_rate) TYPE occ_rate,
|
||||||
|
|
||||||
|
"Method for setter injection
|
||||||
|
setter_meth IMPORTING data_prov TYPE REF TO zdemo_abap_get_data_itf,
|
||||||
|
|
||||||
|
"Method to demonstrate test double injection using parameter injection and a global interface
|
||||||
|
"An optional parameter is specified for passing the test double if the method is tested.
|
||||||
|
get_occ_rate_param_inj IMPORTING carrier_id TYPE zdemo_abap_fli-carrid
|
||||||
|
data_prov TYPE REF TO zdemo_abap_get_data_itf OPTIONAL
|
||||||
RETURNING VALUE(occupancy_rate) TYPE occ_rate.
|
RETURNING VALUE(occupancy_rate) TYPE occ_rate.
|
||||||
|
|
||||||
ENDCLASS.
|
ENDCLASS.
|
||||||
@@ -276,6 +298,33 @@ CLASS zcl_demo_abap_unit_test IMPLEMENTATION.
|
|||||||
|
|
||||||
ENDLOOP.
|
ENDLOOP.
|
||||||
|
|
||||||
|
**********************************************************************
|
||||||
|
|
||||||
|
output->next_section( `8) get_occ_rate_setter_inj Method` ).
|
||||||
|
"This method demonstrates test double injection using setter injection and a global interface.
|
||||||
|
|
||||||
|
LOOP AT tab_str ASSIGNING FIELD-SYMBOL(<g>).
|
||||||
|
|
||||||
|
DATA(occupancy_rate_setter_inj) = get_occ_rate_setter_inj( <g>-carrid ).
|
||||||
|
|
||||||
|
output->display( |The occupancy rate for airline { <g>-carrid } is { occupancy_rate_setter_inj }%.| ).
|
||||||
|
|
||||||
|
ENDLOOP.
|
||||||
|
|
||||||
|
**********************************************************************
|
||||||
|
|
||||||
|
output->next_section( `9) get_occ_rate_param_inj Method` ).
|
||||||
|
"This method demonstrates test double injection using parameter injection and a global interface.
|
||||||
|
|
||||||
|
LOOP AT tab_str ASSIGNING FIELD-SYMBOL(<h>).
|
||||||
|
|
||||||
|
DATA(occupancy_rate_param_inj) = get_occ_rate_param_inj( carrier_id = <h>-carrid ).
|
||||||
|
|
||||||
|
output->display( |The occupancy rate for airline { <h>-carrid } is { occupancy_rate_param_inj }%.| ).
|
||||||
|
|
||||||
|
ENDLOOP.
|
||||||
|
|
||||||
|
|
||||||
ENDMETHOD.
|
ENDMETHOD.
|
||||||
|
|
||||||
METHOD class_constructor.
|
METHOD class_constructor.
|
||||||
@@ -307,6 +356,9 @@ CLASS zcl_demo_abap_unit_test IMPLEMENTATION.
|
|||||||
|
|
||||||
ENDIF.
|
ENDIF.
|
||||||
|
|
||||||
|
"Object creation for the method call in the get_occ_rate_setter_inj method
|
||||||
|
data_provider_setter_inj = NEW lcl_data_prov_glo_itf( ).
|
||||||
|
|
||||||
ENDMETHOD.
|
ENDMETHOD.
|
||||||
|
|
||||||
METHOD get_sum.
|
METHOD get_sum.
|
||||||
@@ -350,10 +402,10 @@ CLASS zcl_demo_abap_unit_test IMPLEMENTATION.
|
|||||||
div += 1.
|
div += 1.
|
||||||
ENDWHILE.
|
ENDWHILE.
|
||||||
|
|
||||||
LOOP AT common_divisors ASSIGNING FIELD-SYMBOL(<g>).
|
LOOP AT common_divisors ASSIGNING FIELD-SYMBOL(<i>).
|
||||||
|
|
||||||
IF greater_num MOD <g> <> 0.
|
IF greater_num MOD <i> <> 0.
|
||||||
DELETE common_divisors WHERE table_line = <g>.
|
DELETE common_divisors WHERE table_line = <i>.
|
||||||
ENDIF.
|
ENDIF.
|
||||||
|
|
||||||
ENDLOOP.
|
ENDLOOP.
|
||||||
@@ -396,10 +448,10 @@ CLASS zcl_demo_abap_unit_test IMPLEMENTATION.
|
|||||||
DATA total_seatsmax_tm TYPE i.
|
DATA total_seatsmax_tm TYPE i.
|
||||||
DATA total_seatsocc_tm TYPE i.
|
DATA total_seatsocc_tm TYPE i.
|
||||||
|
|
||||||
LOOP AT seats_table ASSIGNING FIELD-SYMBOL(<h>).
|
LOOP AT seats_table ASSIGNING FIELD-SYMBOL(<j>).
|
||||||
|
|
||||||
total_seatsmax_tm = total_seatsmax_tm + <h>-seatsmax.
|
total_seatsmax_tm = total_seatsmax_tm + <j>-seatsmax.
|
||||||
total_seatsocc_tm = total_seatsocc_tm + <h>-seatsocc.
|
total_seatsocc_tm = total_seatsocc_tm + <j>-seatsocc.
|
||||||
|
|
||||||
ENDLOOP.
|
ENDLOOP.
|
||||||
|
|
||||||
@@ -453,15 +505,15 @@ CLASS zcl_demo_abap_unit_test IMPLEMENTATION.
|
|||||||
"A local class (lcl_data_prov_local_itf) is also created in the CCIMP include. It
|
"A local class (lcl_data_prov_local_itf) is also created in the CCIMP include. It
|
||||||
"implements the local interface.
|
"implements the local interface.
|
||||||
|
|
||||||
"When running the class with F9, the object used here refers to type lcl_data_prov_local_itf.
|
"When the class is executed using F9, the object used here refers to type lcl_data_prov_local_itf.
|
||||||
"When running the unit test, the object used here refers to type ltd_test_data_local_itf,
|
"When the unit test is executed, the object used here refers to type ltd_test_data_local_itf,
|
||||||
"i.e. the local test double is injected.
|
"i.e. the local test double is injected.
|
||||||
DATA(flight_data) = data_provider_local_itf->select_flight_data( carrier = carrier_id ).
|
DATA(flight_data) = data_provider_local_itf->select_flight_data( carrier = carrier_id ).
|
||||||
|
|
||||||
LOOP AT flight_data ASSIGNING FIELD-SYMBOL(<i>).
|
LOOP AT flight_data ASSIGNING FIELD-SYMBOL(<k>).
|
||||||
|
|
||||||
total_seatsmax_local_itf = total_seatsmax_local_itf + <i>-seatsmax.
|
total_seatsmax_local_itf = total_seatsmax_local_itf + <k>-seatsmax.
|
||||||
total_seatsocc_local_itf = total_seatsocc_local_itf + <i>-seatsocc.
|
total_seatsocc_local_itf = total_seatsocc_local_itf + <k>-seatsocc.
|
||||||
|
|
||||||
ENDLOOP.
|
ENDLOOP.
|
||||||
|
|
||||||
@@ -486,16 +538,15 @@ CLASS zcl_demo_abap_unit_test IMPLEMENTATION.
|
|||||||
"In the example, an interface method is implemented in a local class in the local types
|
"In the example, an interface method is implemented in a local class in the local types
|
||||||
"tab (CCIMP include): lcl_data_prov_glo_itf
|
"tab (CCIMP include): lcl_data_prov_glo_itf
|
||||||
|
|
||||||
"When running the class with F9, the object used here refers to type lcl_data_prov_glo_itf.
|
"When the class is executed using F9, the object used here refers to type lcl_data_prov_glo_itf.
|
||||||
"When running the unit test, the object used here refers to type ltd_test_data_global_intf,
|
"When the unit test is executed, the object used here refers to type ltd_test_data_global_intf,
|
||||||
"i.e. the local test double is injected.
|
"i.e. the local test double is injected.
|
||||||
|
|
||||||
DATA(flight_data) = data_provider_global_itf->select_flight_data( carrier = carrier_id ).
|
DATA(flight_data) = data_provider_global_itf->select_flight_data( carrier = carrier_id ).
|
||||||
|
|
||||||
LOOP AT flight_data ASSIGNING FIELD-SYMBOL(<j>).
|
LOOP AT flight_data ASSIGNING FIELD-SYMBOL(<l>).
|
||||||
|
|
||||||
total_seatsmax_global_itf = total_seatsmax_global_itf + <j>-seatsmax.
|
total_seatsmax_global_itf = total_seatsmax_global_itf + <l>-seatsmax.
|
||||||
total_seatsocc_global_itf = total_seatsocc_global_itf + <j>-seatsocc.
|
total_seatsocc_global_itf = total_seatsocc_global_itf + <l>-seatsocc.
|
||||||
|
|
||||||
ENDLOOP.
|
ENDLOOP.
|
||||||
|
|
||||||
@@ -522,10 +573,10 @@ CLASS zcl_demo_abap_unit_test IMPLEMENTATION.
|
|||||||
"During the unit test, the redefined method in the test class is called.
|
"During the unit test, the redefined method in the test class is called.
|
||||||
DATA(flight_data) = select_flight_data( carrier = carrier_id ).
|
DATA(flight_data) = select_flight_data( carrier = carrier_id ).
|
||||||
|
|
||||||
LOOP AT flight_data ASSIGNING FIELD-SYMBOL(<k>).
|
LOOP AT flight_data ASSIGNING FIELD-SYMBOL(<m>).
|
||||||
|
|
||||||
total_seatsmax_no = total_seatsmax_no + <k>-seatsmax.
|
total_seatsmax_no = total_seatsmax_no + <m>-seatsmax.
|
||||||
total_seatsocc_no = total_seatsocc_no + <k>-seatsocc.
|
total_seatsocc_no = total_seatsocc_no + <m>-seatsocc.
|
||||||
|
|
||||||
ENDLOOP.
|
ENDLOOP.
|
||||||
|
|
||||||
@@ -533,4 +584,83 @@ CLASS zcl_demo_abap_unit_test IMPLEMENTATION.
|
|||||||
|
|
||||||
ENDMETHOD.
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD get_occ_rate_setter_inj.
|
||||||
|
"This method demonstrates test double injection using setting injection.
|
||||||
|
"See the setter_meth method.
|
||||||
|
|
||||||
|
DATA total_seatsmax_setter_inj TYPE i.
|
||||||
|
DATA total_seatsocc_setter_inj TYPE i.
|
||||||
|
|
||||||
|
"Assumption: The original code in this method was as follows (the line commented out).
|
||||||
|
"It was identified as DOC (reading data from a database table).
|
||||||
|
|
||||||
|
"DATA(flight_data) = select_flight_data( carrier = carrier_id ).
|
||||||
|
|
||||||
|
"Instead of a method call like above and for a proper unit testing, a global interface
|
||||||
|
"is provided.
|
||||||
|
"In the example, an interface method is implemented in a local class in the local types
|
||||||
|
"tab (CCIMP include): lcl_data_prov_glo_itf
|
||||||
|
|
||||||
|
"See the comment in the setter_meth method
|
||||||
|
DATA(flight_data) = data_provider_setter_inj->select_flight_data( carrier = carrier_id ).
|
||||||
|
|
||||||
|
LOOP AT flight_data ASSIGNING FIELD-SYMBOL(<n>).
|
||||||
|
|
||||||
|
total_seatsmax_setter_inj = total_seatsmax_setter_inj + <n>-seatsmax.
|
||||||
|
total_seatsocc_setter_inj = total_seatsocc_setter_inj + <n>-seatsocc.
|
||||||
|
|
||||||
|
ENDLOOP.
|
||||||
|
|
||||||
|
occupancy_rate = total_seatsocc_setter_inj / total_seatsmax_setter_inj * 100.
|
||||||
|
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD setter_meth.
|
||||||
|
"Method to demonstrate the test double injection using setter injection
|
||||||
|
|
||||||
|
"When the unit test is executed, an object of the test double class is passed as
|
||||||
|
"a parameter. Then, the object used here refers to type ltd_test_data_setter_inj,
|
||||||
|
"i.e. the local test double is injected.
|
||||||
|
data_provider_setter_inj = data_prov.
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD get_occ_rate_param_inj.
|
||||||
|
"This method demonstrates test double injection using parameter injection.
|
||||||
|
|
||||||
|
DATA total_seatsmax_param_inj TYPE i.
|
||||||
|
DATA total_seatsocc_param_inj TYPE i.
|
||||||
|
|
||||||
|
"Assumption: The original code in this method was as follows (the line commented out).
|
||||||
|
"It was identified as DOC (reading data from a database table).
|
||||||
|
|
||||||
|
"DATA(flight_data) = select_flight_data( carrier = carrier_id ).
|
||||||
|
|
||||||
|
"Instead of a method call like above and for a proper unit testing, a global interface
|
||||||
|
"is provided.
|
||||||
|
"In the example, an interface method is implemented in a local class in the local types
|
||||||
|
"tab (CCIMP include): lcl_data_prov_glo_itf
|
||||||
|
|
||||||
|
"The method has an optional importing parameter. When the unit test is executed,
|
||||||
|
"the parameter is bound. An object of the test double class is passed in that case.
|
||||||
|
"Otherwise, when the class is executed using F9, an object of the actual data provider
|
||||||
|
"is created.
|
||||||
|
IF data_prov IS BOUND.
|
||||||
|
data_provider_param_inj = data_prov.
|
||||||
|
ELSE.
|
||||||
|
data_provider_param_inj = NEW lcl_data_prov_glo_itf( ).
|
||||||
|
ENDIF.
|
||||||
|
|
||||||
|
DATA(flight_data) = data_provider_param_inj->select_flight_data( carrier = carrier_id ).
|
||||||
|
|
||||||
|
LOOP AT flight_data ASSIGNING FIELD-SYMBOL(<o>).
|
||||||
|
|
||||||
|
total_seatsmax_param_inj = total_seatsmax_param_inj + <o>-seatsmax.
|
||||||
|
total_seatsocc_param_inj = total_seatsocc_param_inj + <o>-seatsocc.
|
||||||
|
|
||||||
|
ENDLOOP.
|
||||||
|
|
||||||
|
occupancy_rate = total_seatsocc_param_inj / total_seatsmax_param_inj * 100.
|
||||||
|
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
ENDCLASS.
|
ENDCLASS.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
***********************************************************************
|
***********************************************************************
|
||||||
* Test class overview
|
* Test Class Overview
|
||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
* - This test include contains multiple test classes and methods
|
* - This test include contains multiple test classes and methods
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
* no dependent-on component (DOC).
|
* no dependent-on component (DOC).
|
||||||
*
|
*
|
||||||
* - ltc_test_simple_2
|
* - ltc_test_simple_2
|
||||||
* - Testing mutliple simple methods, no DOCs
|
* - Testing multiple simple methods, no DOCs
|
||||||
* - Special methods setup and teardown
|
* - Special methods setup and teardown
|
||||||
*
|
*
|
||||||
*- ltc_test_dummy
|
*- ltc_test_dummy
|
||||||
@@ -35,20 +35,32 @@
|
|||||||
*- ltc_test_doc_global_itf
|
*- ltc_test_doc_global_itf
|
||||||
* - Testing one method for which a DOC has been identified and for which a global
|
* - Testing one method for which a DOC has been identified and for which a global
|
||||||
* interface exists
|
* interface exists
|
||||||
* - A Local test double class is included
|
* - A local test double class is included
|
||||||
* - Uses constructor injection as injection mechanism
|
* - Demonstrates constructor injection as injection mechanism
|
||||||
*
|
*
|
||||||
*- ltc_test_local_itf
|
*- ltc_test_local_itf
|
||||||
* - Testing one method for which a DOC has been identified
|
* - Testing one method for which a DOC has been identified
|
||||||
* - There is no global interface available. Instead, a local interface is created.
|
* - There is no global interface available. Instead, a local interface is created.
|
||||||
* - A Local test double class is included
|
* - A local test double class is included
|
||||||
* - Uses back door injection as injection mechanism
|
* - Demonstrates back door injection as injection mechanism
|
||||||
*
|
*
|
||||||
*- ltc_test_redef
|
*- ltc_test_redef
|
||||||
* - Testing one method for which a DOC has been identified -
|
* - Testing one method for which a DOC has been identified
|
||||||
* - A local test double class is created by redefining a method of
|
* - A local test double class is created by redefining a method of
|
||||||
* the class under test.
|
* the class under test.
|
||||||
*
|
*
|
||||||
|
*- ltc_test_doc_setter_inj
|
||||||
|
* - Testing one method for which a DOC has been identified and for which a global
|
||||||
|
* interface exists
|
||||||
|
* - A local test double class is included
|
||||||
|
* - Demonstrates setter injection as injection mechanism
|
||||||
|
*
|
||||||
|
*- ltc_test_doc_param_inj
|
||||||
|
* - Testing one method for which a DOC has been identified and for which a global
|
||||||
|
* interface exists
|
||||||
|
* - A local test double class is included
|
||||||
|
* - Demonstrates parameter injection as injection mechanism
|
||||||
|
*
|
||||||
***********************************************************************
|
***********************************************************************
|
||||||
|
|
||||||
"In this example, multiple test classes are created in the test include.
|
"In this example, multiple test classes are created in the test include.
|
||||||
@@ -64,13 +76,17 @@ CLASS ltc_test_doc_seam DEFINITION DEFERRED.
|
|||||||
CLASS ltc_test_doc_global_itf DEFINITION DEFERRED.
|
CLASS ltc_test_doc_global_itf DEFINITION DEFERRED.
|
||||||
CLASS ltc_test_doc_local_itf DEFINITION DEFERRED.
|
CLASS ltc_test_doc_local_itf DEFINITION DEFERRED.
|
||||||
CLASS ltc_test_doc_redef DEFINITION DEFERRED.
|
CLASS ltc_test_doc_redef DEFINITION DEFERRED.
|
||||||
|
CLASS ltc_test_doc_setter_inj DEFINITION DEFERRED.
|
||||||
|
CLASS ltc_test_doc_param_inj DEFINITION DEFERRED.
|
||||||
|
|
||||||
CLASS zcl_demo_abap_unit_test DEFINITION LOCAL FRIENDS ltc_test_simple_1
|
CLASS zcl_demo_abap_unit_test DEFINITION LOCAL FRIENDS ltc_test_simple_1
|
||||||
ltc_test_simple_2
|
ltc_test_simple_2
|
||||||
ltc_test_doc_seam
|
ltc_test_doc_seam
|
||||||
ltc_test_doc_global_itf
|
ltc_test_doc_global_itf
|
||||||
ltc_test_doc_local_itf
|
ltc_test_doc_local_itf
|
||||||
ltc_test_doc_redef.
|
ltc_test_doc_redef
|
||||||
|
ltc_test_doc_setter_inj
|
||||||
|
ltc_test_doc_param_inj.
|
||||||
|
|
||||||
***********************************************************************
|
***********************************************************************
|
||||||
* Test class ltc_test_simple_1
|
* Test class ltc_test_simple_1
|
||||||
@@ -500,7 +516,8 @@ CLASS ltc_test_doc_seam DEFINITION FOR TESTING
|
|||||||
|
|
||||||
PRIVATE SECTION.
|
PRIVATE SECTION.
|
||||||
|
|
||||||
DATA ref_cut TYPE REF TO zcl_demo_abap_unit_test.
|
DATA: ref_cut TYPE REF TO zcl_demo_abap_unit_test,
|
||||||
|
carrier_id TYPE zdemo_abap_fli-carrid.
|
||||||
|
|
||||||
METHODS: test_get_occ_rate_seam_ok FOR TESTING,
|
METHODS: test_get_occ_rate_seam_ok FOR TESTING,
|
||||||
test_get_occ_rate_seam_fail FOR TESTING,
|
test_get_occ_rate_seam_fail FOR TESTING,
|
||||||
@@ -522,7 +539,7 @@ CLASS ltc_test_doc_seam IMPLEMENTATION.
|
|||||||
"The method to be tested calculates the occupancy rate of flights
|
"The method to be tested calculates the occupancy rate of flights
|
||||||
|
|
||||||
"Creating test data
|
"Creating test data
|
||||||
DATA carrier_id TYPE zdemo_abap_fli-carrid VALUE 'AB'.
|
carrier_id = 'AB'.
|
||||||
DATA(expected_occupancy_rate) = '50.00'.
|
DATA(expected_occupancy_rate) = '50.00'.
|
||||||
|
|
||||||
"Injecting test seam into production code by replacing the code that is
|
"Injecting test seam into production code by replacing the code that is
|
||||||
@@ -582,7 +599,7 @@ CLASS ltc_test_doc_seam IMPLEMENTATION.
|
|||||||
"This method intentionally includes values to make the unit test fail.
|
"This method intentionally includes values to make the unit test fail.
|
||||||
|
|
||||||
"Creating test data
|
"Creating test data
|
||||||
DATA carrier_id TYPE zdemo_abap_fli-carrid VALUE 'CD'.
|
carrier_id = 'CD'.
|
||||||
DATA(expected_occupancy_rate) = '60.00'.
|
DATA(expected_occupancy_rate) = '60.00'.
|
||||||
|
|
||||||
"Code injection
|
"Code injection
|
||||||
@@ -632,21 +649,21 @@ ENDCLASS.
|
|||||||
***********************************************************************
|
***********************************************************************
|
||||||
* Test class ltc_test_doc_global_itf
|
* Test class ltc_test_doc_global_itf
|
||||||
*
|
*
|
||||||
* - Tests one method of the global class; uses constructor injection
|
* - Tests one method of the global class; demonstrates constructor injection
|
||||||
* - In this case, a dependent-on component (DOC) has been identified (a
|
* - In this case, a dependent-on component (DOC) has been identified (a
|
||||||
* database access).
|
* database access).
|
||||||
* - A global interface exists to overcome the DOC.
|
* - It is assumed that there is a global interface to overcome the DOC.
|
||||||
* - A local test double class is created. It implements the global
|
* - A local test double class is created. It implements the global
|
||||||
* interface. The method implementation contains manually created test
|
* interface. The method implementation contains manually created test
|
||||||
* data.
|
* data.
|
||||||
*
|
*
|
||||||
* Notes on constructor injection:
|
* Notes on constructor injection in this example:
|
||||||
* - This means that a test double is passed as a parameter to the instance
|
* - This means that a test double is passed as a parameter to the instance
|
||||||
* constructor of the class under test.
|
* constructor of the class under test.
|
||||||
* - An interface reference variable is declared in the private section of
|
* - An interface reference variable is declared in the private section of
|
||||||
* the class under test, and its type references the global interface.
|
* the class under test, and its type references the global interface.
|
||||||
* - A local test class is created here for the test double. It implements
|
* - A local test class is created here for the test double. It implements
|
||||||
* the interface method needed for the test. Note the PARTIALLY IMPLEMENTED
|
* the interface method required by the test. Note the PARTIALLY IMPLEMENTED
|
||||||
* addition to the interface.
|
* addition to the interface.
|
||||||
* - In this method implementation, local test data are created.
|
* - In this method implementation, local test data are created.
|
||||||
* - The global class/class under test has the following instance constructor
|
* - The global class/class under test has the following instance constructor
|
||||||
@@ -700,7 +717,8 @@ CLASS ltc_test_doc_global_itf DEFINITION FOR TESTING
|
|||||||
|
|
||||||
PRIVATE SECTION.
|
PRIVATE SECTION.
|
||||||
DATA: ref_cut TYPE REF TO zcl_demo_abap_unit_test,
|
DATA: ref_cut TYPE REF TO zcl_demo_abap_unit_test,
|
||||||
ref_data_prov TYPE REF TO zdemo_abap_get_data_itf.
|
ref_data_prov TYPE REF TO zdemo_abap_get_data_itf,
|
||||||
|
carrier_id TYPE zdemo_abap_fli-carrid.
|
||||||
|
|
||||||
METHODS: setup,
|
METHODS: setup,
|
||||||
test_get_occ_rate_glo_if_ok FOR TESTING,
|
test_get_occ_rate_glo_if_ok FOR TESTING,
|
||||||
@@ -725,7 +743,8 @@ CLASS ltc_test_doc_global_itf IMPLEMENTATION.
|
|||||||
|
|
||||||
"(1) Calling method that is to be tested
|
"(1) Calling method that is to be tested
|
||||||
"Due to constructor injection, the test double is used.
|
"Due to constructor injection, the test double is used.
|
||||||
DATA(act_occ_rate) = ref_cut->get_occ_rate_global_itf( 'EF' ).
|
carrier_id = 'EF'.
|
||||||
|
DATA(act_occ_rate) = ref_cut->get_occ_rate_global_itf( carrier_id ).
|
||||||
|
|
||||||
"Assertion
|
"Assertion
|
||||||
DATA(exp_value) = '50.00'.
|
DATA(exp_value) = '50.00'.
|
||||||
@@ -733,11 +752,12 @@ CLASS ltc_test_doc_global_itf IMPLEMENTATION.
|
|||||||
cl_abap_unit_assert=>assert_equals(
|
cl_abap_unit_assert=>assert_equals(
|
||||||
act = act_occ_rate
|
act = act_occ_rate
|
||||||
exp = exp_value
|
exp = exp_value
|
||||||
msg = |The expected occupancy rate for carrier EF is wrong.|
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
quit = if_abap_unit_constant=>quit-no ).
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
"(2) Calling method that is to be tested
|
"(2) Calling method that is to be tested
|
||||||
act_occ_rate = ref_cut->get_occ_rate_global_itf( 'GH' ).
|
carrier_id = 'GH'.
|
||||||
|
act_occ_rate = ref_cut->get_occ_rate_global_itf( carrier_id ).
|
||||||
|
|
||||||
"Assertion
|
"Assertion
|
||||||
exp_value = '60.00'.
|
exp_value = '60.00'.
|
||||||
@@ -745,7 +765,7 @@ CLASS ltc_test_doc_global_itf IMPLEMENTATION.
|
|||||||
cl_abap_unit_assert=>assert_equals(
|
cl_abap_unit_assert=>assert_equals(
|
||||||
act = act_occ_rate
|
act = act_occ_rate
|
||||||
exp = exp_value
|
exp = exp_value
|
||||||
msg = |The expected occupancy rate for carrier GH is wrong.|
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
quit = if_abap_unit_constant=>quit-no ).
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
ENDMETHOD.
|
ENDMETHOD.
|
||||||
@@ -754,7 +774,8 @@ CLASS ltc_test_doc_global_itf IMPLEMENTATION.
|
|||||||
"This method intentionally includes values to make the unit test fail.
|
"This method intentionally includes values to make the unit test fail.
|
||||||
|
|
||||||
"(1) Calling method that is to be tested
|
"(1) Calling method that is to be tested
|
||||||
DATA(act_occ_rate) = ref_cut->get_occ_rate_global_itf( 'EF' ).
|
carrier_id = 'EF'.
|
||||||
|
DATA(act_occ_rate) = ref_cut->get_occ_rate_global_itf( carrier_id ).
|
||||||
|
|
||||||
"Assertion to fail
|
"Assertion to fail
|
||||||
DATA(exp_value) = '40.00'. "correct: 50.00
|
DATA(exp_value) = '40.00'. "correct: 50.00
|
||||||
@@ -762,11 +783,12 @@ CLASS ltc_test_doc_global_itf IMPLEMENTATION.
|
|||||||
cl_abap_unit_assert=>assert_equals(
|
cl_abap_unit_assert=>assert_equals(
|
||||||
act = act_occ_rate
|
act = act_occ_rate
|
||||||
exp = exp_value
|
exp = exp_value
|
||||||
msg = |The expected occupancy rate for carrier EF is wrong.|
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
quit = if_abap_unit_constant=>quit-no ).
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
"(2) Calling method that is to be tested
|
"(2) Calling method that is to be tested
|
||||||
act_occ_rate = ref_cut->get_occ_rate_global_itf( 'GH' ).
|
carrier_id = 'GH'.
|
||||||
|
act_occ_rate = ref_cut->get_occ_rate_global_itf( carrier_id ).
|
||||||
|
|
||||||
"Assertion to fail
|
"Assertion to fail
|
||||||
exp_value = '90.00'. "correct: 60.00
|
exp_value = '90.00'. "correct: 60.00
|
||||||
@@ -774,7 +796,7 @@ CLASS ltc_test_doc_global_itf IMPLEMENTATION.
|
|||||||
cl_abap_unit_assert=>assert_equals(
|
cl_abap_unit_assert=>assert_equals(
|
||||||
act = act_occ_rate
|
act = act_occ_rate
|
||||||
exp = exp_value
|
exp = exp_value
|
||||||
msg = |The expected occupancy rate for carrier GH is wrong.|
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
quit = if_abap_unit_constant=>quit-no ).
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
ENDMETHOD.
|
ENDMETHOD.
|
||||||
@@ -784,11 +806,12 @@ ENDCLASS.
|
|||||||
***********************************************************************
|
***********************************************************************
|
||||||
* Test class ltc_test_local_itf
|
* Test class ltc_test_local_itf
|
||||||
*
|
*
|
||||||
* - Tests one method of the global class; uses back door injection
|
* - Tests one method of the global class; demonstrates back door injection
|
||||||
* - In this case, a dependent-on component (DOC) has been identified (a
|
* - In this case, a dependent-on component (DOC) has been identified (a
|
||||||
* database access). The method is similar to the one above.
|
* database access). The method is similar to the one above.
|
||||||
* - There is no global interface to overcome the DOC. Instead, a local
|
* - It is assumed that there is no global interface to overcome the DOC.
|
||||||
* interface is created in the local types (CCIMP include): lif_get_data
|
* Instead, a local interface is created in the local types
|
||||||
|
* (CCIMP include): lif_get_data
|
||||||
* - Additionally, a local class is implemented in the CCIMP include that
|
* - Additionally, a local class is implemented in the CCIMP include that
|
||||||
* implements the local interface. This local class provides the data
|
* implements the local interface. This local class provides the data
|
||||||
* for the method call in the global class (get_occ_rate_local_itf).
|
* for the method call in the global class (get_occ_rate_local_itf).
|
||||||
@@ -798,7 +821,7 @@ ENDCLASS.
|
|||||||
* - In addition, the test class includes a helper method to demonstrate
|
* - In addition, the test class includes a helper method to demonstrate
|
||||||
* the separation of code recurring tasks into separate methods.
|
* the separation of code recurring tasks into separate methods.
|
||||||
*
|
*
|
||||||
* Notes on back door injection:
|
* Notes on back door injection in this example:
|
||||||
* - This means that a back door is created to inject a test double into
|
* - This means that a back door is created to inject a test double into
|
||||||
* the class under test.
|
* the class under test.
|
||||||
* - This back door is implemented by granting friendship to the test
|
* - This back door is implemented by granting friendship to the test
|
||||||
@@ -915,10 +938,11 @@ ENDCLASS.
|
|||||||
***********************************************************************
|
***********************************************************************
|
||||||
* Test class ltc_test_redef
|
* Test class ltc_test_redef
|
||||||
*
|
*
|
||||||
* - Tests one method of the global class; uses constructor injection
|
* - Tests one method of the global class; demonstrates constructor injection
|
||||||
* - In this case, a dependent-on component (DOC) has been identified (a
|
* - In this case, a dependent-on component (DOC) has been identified (a
|
||||||
* database access).
|
* database access).
|
||||||
* - There are no global and local interfaces to overcome the DOC.
|
* - It is assumed that there are no global and local interfaces to overcome
|
||||||
|
* the DOC.
|
||||||
* - A local test double class is created by redefining a method of
|
* - A local test double class is created by redefining a method of
|
||||||
* the class under test. The method implementation contains manually
|
* the class under test. The method implementation contains manually
|
||||||
* created test data.
|
* created test data.
|
||||||
@@ -954,10 +978,10 @@ CLASS ltd_test_data_redef IMPLEMENTATION.
|
|||||||
|
|
||||||
"Providing test data
|
"Providing test data
|
||||||
flight_data = SWITCH #( carrier
|
flight_data = SWITCH #( carrier
|
||||||
WHEN 'UV' THEN VALUE #( ( carrid = carrier seatsmax = 100 seatsocc = 50 )
|
WHEN 'MN' THEN VALUE #( ( carrid = carrier seatsmax = 100 seatsocc = 50 )
|
||||||
( carrid = carrier seatsmax = 200 seatsocc = 150 )
|
( carrid = carrier seatsmax = 200 seatsocc = 150 )
|
||||||
( carrid = carrier seatsmax = 300 seatsocc = 100 ) )
|
( carrid = carrier seatsmax = 300 seatsocc = 100 ) )
|
||||||
WHEN 'WX' THEN VALUE #( ( carrid = carrier seatsmax = 350 seatsocc = 200 )
|
WHEN 'OP' THEN VALUE #( ( carrid = carrier seatsmax = 350 seatsocc = 200 )
|
||||||
( carrid = carrier seatsmax = 350 seatsocc = 250 )
|
( carrid = carrier seatsmax = 350 seatsocc = 250 )
|
||||||
( carrid = carrier seatsmax = 300 seatsocc = 150 ) ) ).
|
( carrid = carrier seatsmax = 300 seatsocc = 150 ) ) ).
|
||||||
|
|
||||||
@@ -973,7 +997,8 @@ CLASS ltc_test_doc_redef DEFINITION FOR TESTING
|
|||||||
DURATION SHORT.
|
DURATION SHORT.
|
||||||
|
|
||||||
PRIVATE SECTION.
|
PRIVATE SECTION.
|
||||||
DATA ref_cut TYPE REF TO zcl_demo_abap_unit_test.
|
DATA: ref_cut TYPE REF TO zcl_demo_abap_unit_test,
|
||||||
|
carrier_id TYPE zdemo_abap_fli-carrid.
|
||||||
|
|
||||||
METHODS: setup,
|
METHODS: setup,
|
||||||
test_get_occ_rate_redef_ok FOR TESTING,
|
test_get_occ_rate_redef_ok FOR TESTING,
|
||||||
@@ -991,48 +1016,367 @@ CLASS ltc_test_doc_redef IMPLEMENTATION.
|
|||||||
|
|
||||||
METHOD test_get_occ_rate_redef_ok.
|
METHOD test_get_occ_rate_redef_ok.
|
||||||
|
|
||||||
DATA(act_occ_rate) = ref_cut->get_occ_rate_using_meth( 'UV' ).
|
carrier_id = 'MN'.
|
||||||
|
DATA(act_occ_rate) = ref_cut->get_occ_rate_using_meth( carrier_id ).
|
||||||
|
|
||||||
DATA(exp_value) = '50.00'.
|
DATA(exp_value) = '50.00'.
|
||||||
|
|
||||||
cl_abap_unit_assert=>assert_equals(
|
cl_abap_unit_assert=>assert_equals(
|
||||||
act = act_occ_rate
|
act = act_occ_rate
|
||||||
exp = exp_value
|
exp = exp_value
|
||||||
msg = |The expected occupancy rate for carrier UV is wrong.|
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
quit = if_abap_unit_constant=>quit-no ).
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
act_occ_rate = ref_cut->get_occ_rate_using_meth( 'WX' ).
|
carrier_id = 'OP'.
|
||||||
|
act_occ_rate = ref_cut->get_occ_rate_using_meth( carrier_id ).
|
||||||
|
|
||||||
exp_value = '60.00'.
|
exp_value = '60.00'.
|
||||||
|
|
||||||
cl_abap_unit_assert=>assert_equals(
|
cl_abap_unit_assert=>assert_equals(
|
||||||
act = act_occ_rate
|
act = act_occ_rate
|
||||||
exp = exp_value
|
exp = exp_value
|
||||||
msg = |The expected occupancy rate for carrier WX is wrong.|
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
quit = if_abap_unit_constant=>quit-no ).
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
ENDMETHOD.
|
ENDMETHOD.
|
||||||
|
|
||||||
METHOD test_get_occ_rate_redef_fail.
|
METHOD test_get_occ_rate_redef_fail.
|
||||||
|
|
||||||
DATA(act_occ_rate) = ref_cut->get_occ_rate_using_meth( 'UV' ).
|
carrier_id = 'MN'.
|
||||||
|
DATA(act_occ_rate) = ref_cut->get_occ_rate_using_meth( carrier_id ).
|
||||||
|
|
||||||
DATA(exp_value) = '40.00'. "correct: 50.00
|
DATA(exp_value) = '40.00'. "correct: 50.00
|
||||||
|
|
||||||
cl_abap_unit_assert=>assert_equals(
|
cl_abap_unit_assert=>assert_equals(
|
||||||
act = act_occ_rate
|
act = act_occ_rate
|
||||||
exp = exp_value
|
exp = exp_value
|
||||||
msg = |The expected occupancy rate for carrier UV is wrong.|
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
quit = if_abap_unit_constant=>quit-no ).
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
act_occ_rate = ref_cut->get_occ_rate_using_meth( 'WX' ).
|
carrier_id = 'OP'.
|
||||||
|
act_occ_rate = ref_cut->get_occ_rate_using_meth( carrier_id ).
|
||||||
|
|
||||||
exp_value = '90.00'. "correct: 60.00
|
exp_value = '90.00'. "correct: 60.00
|
||||||
|
|
||||||
cl_abap_unit_assert=>assert_equals(
|
cl_abap_unit_assert=>assert_equals(
|
||||||
act = act_occ_rate
|
act = act_occ_rate
|
||||||
exp = exp_value
|
exp = exp_value
|
||||||
msg = |The expected occupancy rate for carrier WX is wrong.|
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
* Test class ltc_test_doc_setter_inj
|
||||||
|
*
|
||||||
|
* - Tests one method of the global class; demonstrates setter injection
|
||||||
|
* - In this case, a dependent-on component (DOC) has been identified (a
|
||||||
|
* database access).
|
||||||
|
* - It is assumed that there is a global interface to overcome the DOC.
|
||||||
|
* - A local test double class is created. It implements the global
|
||||||
|
* interface. The method implementation contains manually created test
|
||||||
|
* data.
|
||||||
|
*
|
||||||
|
* Notes on setter injection in this example:
|
||||||
|
* - This means that an object of the test double class is passed as a
|
||||||
|
* parameter to a setter method in the class under test.
|
||||||
|
* - An interface reference variable is declared in the private section of
|
||||||
|
* the class under test, and its type references the global interface.
|
||||||
|
* - A local test class is created here for the test double. It implements
|
||||||
|
* the interface method required by the test. Note the PARTIALLY IMPLEMENTED
|
||||||
|
* addition to the interface.
|
||||||
|
* - In this method implementation, local test data are created.
|
||||||
|
* - The global class/class under test contains a setter method (setter_meth)
|
||||||
|
* that has an importing parameter of type reference to the global interface.
|
||||||
|
* - When the unit test is executed (and only then), the setter method is
|
||||||
|
* called in the test class. Before the call is made, an object of the
|
||||||
|
* test double class is created. This object is passed to the setter method.
|
||||||
|
* - In the implementation of the setter method, the interface variable declared in
|
||||||
|
* the private section of the class under test is assigned the object of
|
||||||
|
* the test double class. When the method is 'usually' called
|
||||||
|
* (i.e., not in the context of a unit test), for example, when the
|
||||||
|
* class is run using F9, the instance constructor implementation involves
|
||||||
|
* creating an object of the actual data provider that is assigned to
|
||||||
|
* the interface variable. Therefore, when the unit test is executed, the
|
||||||
|
* assigned object is replaced by the setter method and the test double
|
||||||
|
* is used instead.
|
||||||
|
***********************************************************************
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
* Local test double class
|
||||||
|
***********************************************************************
|
||||||
|
CLASS ltd_test_data_setter_inj DEFINITION FOR TESTING.
|
||||||
|
PUBLIC SECTION.
|
||||||
|
|
||||||
|
"Note: Usually, you must implement all non-optional methods of interfaces.
|
||||||
|
"Without the addition PARTIALLY IMPLEMENTED, there would be a syntax error.
|
||||||
|
INTERFACES zdemo_abap_get_data_itf PARTIALLY IMPLEMENTED.
|
||||||
|
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
CLASS ltd_test_data_setter_inj IMPLEMENTATION.
|
||||||
|
METHOD zdemo_abap_get_data_itf~select_flight_data.
|
||||||
|
|
||||||
|
CLEAR flight_data.
|
||||||
|
|
||||||
|
"Providing test data
|
||||||
|
flight_data = SWITCH #( carrier
|
||||||
|
WHEN 'QR' THEN VALUE #( ( carrid = carrier seatsmax = 100 seatsocc = 50 )
|
||||||
|
( carrid = carrier seatsmax = 200 seatsocc = 150 )
|
||||||
|
( carrid = carrier seatsmax = 300 seatsocc = 100 ) )
|
||||||
|
WHEN 'ST' THEN VALUE #( ( carrid = carrier seatsmax = 350 seatsocc = 200 )
|
||||||
|
( carrid = carrier seatsmax = 350 seatsocc = 250 )
|
||||||
|
( carrid = carrier seatsmax = 300 seatsocc = 150 ) ) ).
|
||||||
|
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
* Test class ltc_test_doc_setter_inj
|
||||||
|
***********************************************************************
|
||||||
|
CLASS ltc_test_doc_setter_inj DEFINITION FOR TESTING
|
||||||
|
RISK LEVEL HARMLESS
|
||||||
|
DURATION SHORT.
|
||||||
|
|
||||||
|
PRIVATE SECTION.
|
||||||
|
DATA: ref_cut TYPE REF TO zcl_demo_abap_unit_test,
|
||||||
|
ref_data_prov TYPE REF TO zdemo_abap_get_data_itf,
|
||||||
|
carrier_id TYPE zdemo_abap_fli-carrid.
|
||||||
|
|
||||||
|
METHODS: setup,
|
||||||
|
test_get_occ_rate_set_inj_ok FOR TESTING,
|
||||||
|
test_get_occ_rate_set_inj_fail FOR TESTING.
|
||||||
|
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
CLASS ltc_test_doc_setter_inj IMPLEMENTATION.
|
||||||
|
|
||||||
|
METHOD setup.
|
||||||
|
|
||||||
|
ref_cut = NEW #( ).
|
||||||
|
|
||||||
|
"Creating an instance of the local test double
|
||||||
|
ref_data_prov = NEW ltd_test_data_setter_inj( ).
|
||||||
|
|
||||||
|
"Setter injection
|
||||||
|
"Passing the test double as a parameter of a setter method
|
||||||
|
ref_cut->setter_meth( ref_data_prov ).
|
||||||
|
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD test_get_occ_rate_set_inj_ok.
|
||||||
|
"The method to be tested calculates the occupancy rate of flights.
|
||||||
|
|
||||||
|
"(1) Calling method that is to be tested
|
||||||
|
"Due to constructor injection, the test double is used.
|
||||||
|
carrier_id = 'QR'.
|
||||||
|
DATA(act_occ_rate) = ref_cut->get_occ_rate_setter_inj( carrier_id ).
|
||||||
|
|
||||||
|
"Assertion
|
||||||
|
DATA(exp_value) = '50.00'.
|
||||||
|
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
act = act_occ_rate
|
||||||
|
exp = exp_value
|
||||||
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
|
"(2) Calling method that is to be tested
|
||||||
|
carrier_id = 'ST'.
|
||||||
|
act_occ_rate = ref_cut->get_occ_rate_setter_inj( carrier_id ).
|
||||||
|
|
||||||
|
"Assertion
|
||||||
|
exp_value = '60.00'.
|
||||||
|
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
act = act_occ_rate
|
||||||
|
exp = exp_value
|
||||||
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD test_get_occ_rate_set_inj_fail.
|
||||||
|
"This method intentionally includes values to make the unit test fail.
|
||||||
|
|
||||||
|
"(1) Calling method that is to be tested
|
||||||
|
carrier_id = 'QR'.
|
||||||
|
DATA(act_occ_rate) = ref_cut->get_occ_rate_setter_inj( carrier_id ).
|
||||||
|
|
||||||
|
"Assertion to fail
|
||||||
|
DATA(exp_value) = '40.00'. "correct: 50.00
|
||||||
|
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
act = act_occ_rate
|
||||||
|
exp = exp_value
|
||||||
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
|
"(2) Calling method that is to be tested
|
||||||
|
carrier_id = 'ST'.
|
||||||
|
act_occ_rate = ref_cut->get_occ_rate_setter_inj( carrier_id ).
|
||||||
|
|
||||||
|
"Assertion to fail
|
||||||
|
exp_value = '90.00'. "correct: 60.00
|
||||||
|
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
act = act_occ_rate
|
||||||
|
exp = exp_value
|
||||||
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
* Test class ltc_test_doc_param_inj
|
||||||
|
*
|
||||||
|
* - Tests one method of the global class; demonstrates parameter injection
|
||||||
|
* - In this case, a dependent-on component (DOC) has been identified (a
|
||||||
|
* database access).
|
||||||
|
* - It is assumed that there is a global interface to overcome the DOC.
|
||||||
|
* - A local test double class is created. It implements the global
|
||||||
|
* interface. The method implementation contains manually created test
|
||||||
|
* data.
|
||||||
|
*
|
||||||
|
* Notes on parameter injection in this example:
|
||||||
|
* - This means that an object of the test double class is passed as a
|
||||||
|
* parameter of the tested method in the class under test.
|
||||||
|
* - This parameter is optional. When the unit test is run, the parameter
|
||||||
|
* is bound. An object of the test double class is passed in this case.
|
||||||
|
* Otherwise, when the method is 'usually' called (i.e., not in the
|
||||||
|
* context of a unit test), for example, when the class is run using F9,
|
||||||
|
* the parameter is not bound. Then, an object of the actual data
|
||||||
|
* provider is created. The method in the class under test contains a
|
||||||
|
* check in the implementation (IF ... IS BOUND ...).
|
||||||
|
***********************************************************************
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
* Local test double class
|
||||||
|
***********************************************************************
|
||||||
|
CLASS ltd_test_data_param_inj DEFINITION FOR TESTING.
|
||||||
|
PUBLIC SECTION.
|
||||||
|
|
||||||
|
"Note: Usually, you must implement all non-optional methods of interfaces.
|
||||||
|
"Without the addition PARTIALLY IMPLEMENTED, there would be a syntax error.
|
||||||
|
INTERFACES zdemo_abap_get_data_itf PARTIALLY IMPLEMENTED.
|
||||||
|
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
CLASS ltd_test_data_param_inj IMPLEMENTATION.
|
||||||
|
METHOD zdemo_abap_get_data_itf~select_flight_data.
|
||||||
|
|
||||||
|
CLEAR flight_data.
|
||||||
|
|
||||||
|
"Providing test data
|
||||||
|
flight_data = SWITCH #( carrier
|
||||||
|
WHEN 'UV' THEN VALUE #( ( carrid = carrier seatsmax = 100 seatsocc = 50 )
|
||||||
|
( carrid = carrier seatsmax = 200 seatsocc = 150 )
|
||||||
|
( carrid = carrier seatsmax = 300 seatsocc = 100 ) )
|
||||||
|
WHEN 'WX' THEN VALUE #( ( carrid = carrier seatsmax = 350 seatsocc = 200 )
|
||||||
|
( carrid = carrier seatsmax = 350 seatsocc = 250 )
|
||||||
|
( carrid = carrier seatsmax = 300 seatsocc = 150 ) ) ).
|
||||||
|
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
***********************************************************************
|
||||||
|
* Test class ltc_test_doc_param_inj
|
||||||
|
***********************************************************************
|
||||||
|
CLASS ltc_test_doc_param_inj DEFINITION FOR TESTING
|
||||||
|
RISK LEVEL HARMLESS
|
||||||
|
DURATION SHORT.
|
||||||
|
|
||||||
|
PRIVATE SECTION.
|
||||||
|
DATA: ref_cut TYPE REF TO zcl_demo_abap_unit_test,
|
||||||
|
ref_data_prov TYPE REF TO zdemo_abap_get_data_itf,
|
||||||
|
carrier_id TYPE zdemo_abap_fli-carrid.
|
||||||
|
|
||||||
|
METHODS: setup,
|
||||||
|
test_get_occ_rate_par_inj_ok FOR TESTING,
|
||||||
|
test_get_occ_rate_par_inj_fail FOR TESTING.
|
||||||
|
|
||||||
|
ENDCLASS.
|
||||||
|
|
||||||
|
CLASS ltc_test_doc_param_inj IMPLEMENTATION.
|
||||||
|
|
||||||
|
METHOD setup.
|
||||||
|
|
||||||
|
ref_cut = NEW #( ).
|
||||||
|
|
||||||
|
"Creating an instance of the local test double
|
||||||
|
ref_data_prov = NEW ltd_test_data_param_inj( ).
|
||||||
|
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD test_get_occ_rate_par_inj_ok.
|
||||||
|
"The method to be tested calculates the occupancy rate of flights.
|
||||||
|
|
||||||
|
"(1) Calling method that is to be tested
|
||||||
|
"Due to constructor injection, the test double is used.
|
||||||
|
carrier_id = 'UV'.
|
||||||
|
DATA(act_occ_rate) = ref_cut->get_occ_rate_param_inj( carrier_id = carrier_id
|
||||||
|
data_prov = ref_data_prov ).
|
||||||
|
|
||||||
|
"Assertion
|
||||||
|
DATA(exp_value) = '50.00'.
|
||||||
|
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
act = act_occ_rate
|
||||||
|
exp = exp_value
|
||||||
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
|
"(2) Calling method that is to be tested
|
||||||
|
carrier_id = 'WX'.
|
||||||
|
act_occ_rate = ref_cut->get_occ_rate_param_inj( carrier_id = carrier_id
|
||||||
|
data_prov = ref_data_prov ).
|
||||||
|
|
||||||
|
"Assertion
|
||||||
|
exp_value = '60.00'.
|
||||||
|
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
act = act_occ_rate
|
||||||
|
exp = exp_value
|
||||||
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
|
ENDMETHOD.
|
||||||
|
|
||||||
|
METHOD test_get_occ_rate_par_inj_fail.
|
||||||
|
"This method intentionally includes values to make the unit test fail.
|
||||||
|
|
||||||
|
"(1) Calling method that is to be tested
|
||||||
|
carrier_id = 'UV'.
|
||||||
|
DATA(act_occ_rate) = ref_cut->get_occ_rate_param_inj( carrier_id = carrier_id
|
||||||
|
data_prov = ref_data_prov ).
|
||||||
|
|
||||||
|
"Assertion to fail
|
||||||
|
DATA(exp_value) = '40.00'. "correct: 50.00
|
||||||
|
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
act = act_occ_rate
|
||||||
|
exp = exp_value
|
||||||
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
|
"(2) Calling method that is to be tested
|
||||||
|
carrier_id = 'WX'.
|
||||||
|
act_occ_rate = ref_cut->get_occ_rate_param_inj( carrier_id = carrier_id
|
||||||
|
data_prov = ref_data_prov ).
|
||||||
|
|
||||||
|
"Assertion to fail
|
||||||
|
exp_value = '90.00'. "correct: 60.00
|
||||||
|
|
||||||
|
cl_abap_unit_assert=>assert_equals(
|
||||||
|
act = act_occ_rate
|
||||||
|
exp = exp_value
|
||||||
|
msg = |The expected occupancy rate for carrier { carrier_id } is wrong.|
|
||||||
quit = if_abap_unit_constant=>quit-no ).
|
quit = if_abap_unit_constant=>quit-no ).
|
||||||
|
|
||||||
ENDMETHOD.
|
ENDMETHOD.
|
||||||
|
|||||||
Reference in New Issue
Block a user