ABAP Unit - TDF (SQL Double)
In this article we take a closer look at the SQL Double and how you can gain independence from the database.
The Test Double Framework (for short TDF) provides tools to generate so-called doubles for the objects class, table and core data service (CDS) during the test period and to test them against them. This technique is intended to reduce dependencies on objects that are difficult to test and focus on testing the actual component (class).
The SQL double has the task of replacing the database layer and thus replacing all requests (CRUD) on one or more tables with a corresponding double. The tables can be specified during generation. The following overview of the actual test:
Point 1) shows the normal test scenario without the test double, the accesses of the code under test always go to the correct data in the database. Point 2) shows the goal, we have exchanged the data in the table with a double, all CRUD operations run against the double and are thus secured by us.
However, we do not exchange the data directly on the database; it is available at all times and remains consistent. The generated test double is available to us for our test class and is removed again after it has been carried out.
The advantage of this technique is the stability of our test cases, as we cannot be sure that our test data in the database will not change. With this technique, the data for our tests always remains the same and you do not have to outsource access to the database to other classes or even adjust them.
In order to bring you closer to the use of the methodology, we want to illustrate the topic with an example. We want to replace the following table with a double:
The table contains some data sets that should be sufficient for our tests:
For this purpose, we are now building a corresponding class against which we can then run our test class. For this we only need a simple reading routine, to which we transfer a key and then receive the result of the database selection.
CLASS zcl_bs_demo_double_sql DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. METHODS: select_tool IMPORTING id_sname TYPE char25 RETURNING VALUE(rs_tool) TYPE zbs_dy_tools. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_bs_demo_double_sql IMPLEMENTATION. METHOD select_tool. SELECT SINGLE * FROM zbs_dy_tools WHERE short_name = @id_sname INTO @rs_tool. ENDMETHOD. ENDCLASS.
The corresponding test class now looks like this.
CLASS ltc_db_access DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. PRIVATE SECTION. CLASS-DATA: go_environment TYPE REF TO if_osql_test_environment. CLASS-METHODS: class_setup, class_teardown. METHODS: positive_case FOR TESTING, negative_case FOR TESTING. ENDCLASS. CLASS ltc_db_access IMPLEMENTATION. METHOD class_setup. DATA: lt_data TYPE STANDARD TABLE OF zbs_dy_tools WITH EMPTY KEY. go_environment = cl_osql_test_environment=>create( VALUE #( ( 'ZBS_DY_TOOLS' ) ) ). lt_data = VALUE #( ( short_name = 'SAW' stock_quantity = 15 ) ( short_name = 'WRENCH' stock_quantity = 0 ) ( short_name = 'NAIL' stock_quantity = 250 ) ). go_environment->insert_test_data( lt_data ). ENDMETHOD. METHOD class_teardown. go_environment->destroy( ). ENDMETHOD. METHOD positive_case. DATA(lo_cut) = NEW zcl_bs_demo_double_sql( ). DATA(ls_result) = lo_cut->select_tool( 'NAIL' ). cl_abap_unit_assert=>assert_not_initial( ls_result ). ENDMETHOD. METHOD negative_case. DATA(lo_cut) = NEW zcl_bs_demo_double_sql( ). DATA(ls_result) = lo_cut->select_tool( 'HAMMER' ). cl_abap_unit_assert=>assert_initial( ls_result ). ENDMETHOD. ENDCLASS.
As you can see in the example above, a few steps are necessary for the preparation and we use the help methods CLASS_SETUP and CLASS_TEARDOWN for this.
- In the setup method, the SQL environment is first set up and the tables to be exchanged are specified
- Transfer of the test data to the environment
- Execution of the test cases against the test data
- Breakdown of the environment when breaking down the test class
The data can also be made available in SETUP, for this purpose the data is transferred to the method and the SQL double is cleared beforehand with CLEAR_DOUBLES. The method deletes the existing data and empties all tables. Deleting the data from the table is mainly used when you want to test CRUD operations against the tables.
With the test double framework, you can bridge and exchange various components during the test period in order to reduce the test to your code. With the SQL Double you make sure that your accesses find the data you want.