Application Development and Automation Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

How to test cds table function?

friendlycoder
Participant
7,443

Hi All
I've created the CDS table function and would like to write unit test for it:

define table function Z_COMP_CODE
  with parameters
    @Environment.systemField: #CLIENT
    clnt    : abap.clnt,
    sel_opt : abap.char( 1000 )
returns
{
  Client         : abap.clnt;
  CompanyCodeOld : bukrs;
  ProfitCenter   : prctr;
  ValidFrom      : datab;
  ValidTo        : datbi;
  CompanyCodeNew : bukrs;
}
implemented by method
  ycl_cme_table_function=>QUERY_COMPANY_CODE; 

Is it possible to write unit test for table functions?

Thanks

21 REPLIES 21
Read only

former_member1716
Active Contributor
0 Likes
5,742

Hello Anujit Marty,

Of Course you can, One simple way is write a test program where you have the required fields in the select Option. Now dynamically you have to wrap the select Option and feed into the parameters of CDS. Inside the table function method you have to use APPLY_FILTER function to apply the select options.

You can refer the below Blog which will guide you on the same.

CDS_TABLE_FUNCTION

Regards!

Read only

FredericGirod
Active Contributor
Read only

5,742

In case the hyperlink goes wrong in the future, the chapter is "Writing Unit Tests Using CDS Test Double Framework"

Read only

0 Likes
5,742

There is always dead link in the forum, wonder if we could create it differently ...

Read only

0 Likes
5,742

How to create abap test class for table function?

On the CDS View, you can create a ABAP Test Class but for table function not:

2019-10-31-11-41-39.png

Read only

0 Likes
5,742

I never try, it is a next chapter of my book 😉

Core Data Services for ABAP (SAP Press)

Read only

0 Likes
5,742

Anujit Marty The documentation of method INSERT_TEST_DATA of IF_CDS_TEST_ENVIRONMENT says: "If the dependency is of type cds view or cds table function with input parameters, also provide the test data for the input parameters. Test_data for parameters will get matched against the actual parameter values by which the dependent CDS View or CDS table function is called during execution. If only both matches, the double will return the test_data."

Read only

0 Likes
5,742

sandra.rossi Could you please try to create a cds table function and then create in addition ABAP Test Class.
I can not even create the ABAP Test Class. It is impossible, please try.

Read only

0 Likes
5,742

You have a blog on this subject here https://blogs.sap.com/2018/08/30/cds-doubles-writing-unit-tests-for-abap-cds/

the interface if_cds_test_environment is unknown in my SAP Release

Read only

0 Likes
5,742

I've tried as follow:

METHOD query_with_valid_data.
    data lo_environment type ref to if_cds_test_environment.
    lo_environment = cl_cds_test_environment=>create( i_for_entity = 'YCME_FN_COMP_CODE' ).
    break-POINT.
ENDMETHOD.

And the compiler complains:

Testing of table functions is not supported
Read only

0 Likes
5,742

Anujit Marty See my reply, in a distinct answer. In fact, the CDS test double framework doesn't seem to work for table functions... (at least in my S/4HANA 7.52 SP0 system)

Read only

0 Likes
5,742

EDIT: Anujit Marty oops sorry, I was wrong. I edited my distinct answer, with a working example.

Read only

Sandra_Rossi
Active Contributor
5,742

EDIT: this answer is wrong because I don't test the CDS Table Function, I just mock it. Thank you szebenyi_balint for notifying (see comments). Currently, I don't know how to test the CDS Table Function, sorry !

Original obsolete answer:

I could make the Unit Test of CDS Table Function work.

I had to wrap it in a CDS View.

I created a test environment for this CDS view, and inserted data for the CDS Table Function: you inject data to be returned based on the input parameters.

CDS Table Function:

define table function Z_COMP_CODE
  with parameters
    @Environment.systemField: #CLIENT
    clnt    : abap.clnt,
    sel_opt : abap.char( 1000 )
returns
{
  mandt : abap.clnt;
  carrid : s_carr_id;
}
implemented by method
  ycl_cme_table_function=>QUERY_COMPANY_CODE;

AMDP Class:

CLASS ycl_cme_table_function DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .
  PUBLIC SECTION.
    INTERFACES: if_amdp_marker_hdb.
    CLASS-METHODS query_company_code FOR TABLE FUNCTION z_comp_code.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.
CLASS ycl_cme_table_function IMPLEMENTATION.
  METHOD query_company_code BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY
  USING scarr.
    lt_scarr = apply_filter( scarr, :sel_opt );
    RETURN SELECT mandt, carrid FROM :lt_scarr;
  ENDMETHOD.
ENDCLASS.

CDS View:

@AbapCatalog.sqlViewName: 'Z_COMP_CODEVIEW2'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'CDS view'
define view Z_COMP_CODE_VIEW
    with parameters sel_opt : abap.char(1000)
as select from Z_COMP_CODE( clnt: $session.client, sel_opt: $parameters.sel_opt) {
    mandt,
    carrid
}<br>

ABAP code:

CLASS lcl_app DEFINITION.
  PUBLIC SECTION.
    TYPES: ty_s_carrid        TYPE RANGE OF scarr-carrid,
           ty_z_comp_code_tab TYPE STANDARD TABLE OF z_comp_code WITH EMPTY KEY.
    METHODS get_z_comp_code_tab
      IMPORTING
        s_carrid               TYPE ty_s_carrid
      RETURNING
        VALUE(z_comp_code_tab) TYPE ty_z_comp_code_tab.
ENDCLASS.
CLASS lcl_app IMPLEMENTATION.
  METHOD get_z_comp_code_tab.
    DATA : lt_tab  TYPE TABLE OF z_comp_code,
           l_where TYPE string.
    " Example if s_carrid = VALUE #( ( sign = 'I' option = 'CP' low = 'A*' ) )
    " and current client = '100', l_where will have value: MANDT = '100' AND ( CARRID LIKE 'A%')
    l_where = cl_shdb_seltab=>combine_seltabs(
          it_named_seltabs = VALUE #( ( name = 'CARRID' dref = REF #( s_carrid[] ) ) )
          iv_client_field = 'MANDT' ).
    SELECT *
        FROM z_comp_code_view( sel_opt = @l_where )
        INTO TABLE @z_comp_code_tab
        ##db_feature_mode[amdp_table_function].
  ENDMETHOD.
ENDCLASS.

CLASS ltc_main DEFINITION
      FOR TESTING
      DURATION SHORT
      RISK LEVEL HARMLESS.
  PRIVATE SECTION.
    METHODS: setup,
      test FOR TESTING.
    CLASS-DATA: environment TYPE REF TO if_cds_test_environment.
    CLASS-METHODS: class_setup,
      class_teardown.
ENDCLASS.
CLASS ltc_main IMPLEMENTATION.
  METHOD class_setup.
    environment = cl_cds_test_environment=>create(
        i_for_entity = 'Z_COMP_CODE_VIEW' ). " The CDS view (calling the table function)
  ENDMETHOD.
  METHOD test.
    TYPES: ty_scarr_tab TYPE STANDARD TABLE OF scarr WITH EMPTY KEY.
    environment->insert_test_data( " stub the CDS Table Function Z_COMP_CODE
        i_data = VALUE lcl_app=>ty_z_comp_code_tab(
            ( carrid = 'AY' ) )
        i_parameter_values = VALUE #(
            ( parameter_name = 'CLNT'    parameter_value = sy-mandt )
            ( parameter_name = 'SEL_OPT' parameter_value = |MANDT = '{ sy-mandt }' AND ( CARRID LIKE 'A%')| ) ) ).
    DATA(z_comp_code_tab) = NEW lcl_app( )->get_z_comp_code_tab( VALUE #( ( sign = 'I' option = 'CP' low = 'A*' ) ) ).
    cl_abap_unit_assert=>assert_equals(
        act = z_comp_code_tab
        exp = VALUE lcl_app=>ty_z_comp_code_tab( ( carrid = 'AY' ) ) ).
  ENDMETHOD.
  METHOD class_teardown.
    environment->destroy( ).
  ENDMETHOD.
  METHOD setup.
    environment->clear_doubles( ).
  ENDMETHOD.
ENDCLASS.

DATA : carrid TYPE scarr-carrid.
SELECT-OPTIONS : s_carrid FOR carrid.

START-OF-SELECTION.
  NEW lcl_app( )->get_z_comp_code_tab( s_carrid[] ). 
Read only

0 Likes
5,742

SAP does not support unit test for table function?

Read only

0 Likes
5,742

Anujit Marty No, sorry, it works. See the last version of my answer.

Read only

5,742

sandra.rossi Awesome thanks a lot.

Read only

0 Likes
5,742

Sorry but this is not testing the table function. The table function is mocked out and it stands in the comment in the ABAP code as well. If you stub out the tf behind the view then you are not testing the logic in the table function!

Observe that the test environment holds a double for the tf. Try putting an AMDP breakpoint in the AMDP method it won't stop there while unit testing, since that is mocked out, but when you run the report it will stop at the AMDP breakpoint during that real usage.

So this example is not good for unit testing it lures you into the illusion that your tf works whereas what you are doing is you are telling the system that the tf will always give back AY which you then verify that it indeed gives back AY - this is definitely a false hope regarding the tf's behaviour.

Read only

0 Likes
5,742
szebenyi_balint Maybe you're right but I don't get what you exactly mean. In the example, the table function calls an AMDP method with "apply_filter" to select from table SCARR filtered by a Range Table.The test shows that with table SCARR mocked with AY line, if the table function is called with range sign = 'I' option = 'CP' low = 'A*', it returns AY. So the test does what I expected: it shows that the table function applies the filter correctly. Of course it's just a test for a complete demonstration, it makes no sense to create a test method to test "apply_filter".Could you share another example of table function that could better support your case?
Read only

5,742

The code mocks the tf so that when it receives those parameters it will return AY - independent of the tf coding. So the actual tf is not called but mocked out. This code does not test the logic inside the tf, just checks if it is called with those parameters - in which case it returns AY.

Try removing the inner part of the tf and run the unit tests.

Read only

Sandra_Rossi
Active Contributor
5,742

I couldn't successfully unit test the CDS table function. I recommend to ask the SAP author in this blog post: https://blogs.sap.com/2016/10/19/introduction-cds-test-double-framework-write-unit-tests-abap-cds-en...

Read only

raphael_almeida
Active Contributor
0 Likes
5,742

I agree with sandra.rossi. Following the metioned blog you can make your test bifunctor 🙂