cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

How to Unit test RAP managed BDEF Class, with custom action

phil_soady
Participant
0 Likes
1,047

I have been tryin to UNIT test a Method in a BDEF Implementation class.

Tutorials reviewed include:
https://developers.sap.com/tutorials/abap-environment-rap100-unit-testing..html
https://community.sap.com/t5/technology-blogs-by-sap/abap-units-in-abap-restful-programming-model/ba...
https://help.sap.com/docs/ABAP_PLATFORM_NEW/fc4c71aa50014fd1b43721701471913d/6477e7b5f4594498973ce5c...
Ive looked at similar code in /dmo/bp_travel_m  Test classes and similar examples on github.

I have been trying for many hours to get unit testing working on  a generated BDEF implementation class.
And I cant get the READ ENTITIES to use Mock data from a unit test.

Background:
I started with a simple table with a generated Business Configuration.
Similar to this https://developers.sap.com/tutorials/abap-environment-business-configuration-object..html

My configuration maintenance object and it UI is working.
The BDEF that was generated has an extension.
custom validation extras are common. See posts like 
https://community.sap.com/t5/technology-blogs-by-members/how-to-perform-field-validation-in-abap-res...

The BDEF, and what I added: 
  

 

 

 validation CheckIntfNameAndClassName on save { create; update; }  <<<<ADDED
  draft determine action Prepare { 
    validation FactoryOverride ~ ValidateDataConsistency;
    validation CheckIntfNameAndClassName;   <<<< ADDED
  }

 

 


He is the FULL BDEF

 

 

managed with additional save implementation in class /OXO/BP_I_FACTORYCUSTOV_S unique;
strict;
with draft;
define behavior for /OXO/I_FactoryCustOv_S alias FactoryCustOvAll
draft table /OXO/D_FACTORY_S
with unmanaged save
lock master total etag LastChangedAtMax
authorization master( global )
{
  field ( readonly )
   SingletonID,
   TransportRequestID;

  field ( notrigger )
   SingletonID,
   HideTransport,
   LastChangedAtMax;

  update;
  internal create;
  internal delete;

  draft action ( features : instance ) Edit;
  draft action Activate optimized;
  draft action Discard;
  draft action Resume;
  validation CheckIntfNameAndClassName on save { create; update; }
  draft determine action Prepare {
    validation FactoryOverride ~ ValidateDataConsistency;
    validation CheckIntfNameAndClassName;
  }
  action ( features : instance ) SelectCustomizingTransptReq parameter D_SelectCustomizingTransptReqP result [1] $self;
  association _FactoryOverride { create ( features : instance ); with draft; }
}
define behavior for /OXO/I_FactoryOverride alias FactoryOverride
persistent table /OXO/FACTORYCUST
draft table /OXO/D_FACTORYCU
etag master LocalLastChangedAt
lock dependent by _FactoryCustOvAll
authorization dependent by _FactoryCustOvAll
{
  field ( mandatory : create )
   IntfName;
  field ( readonly )
   SingletonID,
   CreatedBy,
   CreatedAt,
   LastChangedBy,
   LastChangedAt,
   LocalLastChangedBy,
   LocalLastChangedAt;
  field ( readonly : update )
   BusinessContext,
   IntfName;
  field ( notrigger )
   SingletonID,
   CreatedBy,
   CreatedAt,
   LastChangedBy,
   LastChangedAt,
   LocalLastChangedBy,
   LocalLastChangedAt;
  update( features : global );
  delete( features : global );
  mapping for /OXO/FACTORYCUST
  {
    BusinessContext = BUSINESS_CONTEXT;
    IntfName = INTF_NAME;
    UseSingleton = USE_SINGLETON;
    ClassName = CLASS_NAME;
    CreatedBy = CREATED_BY;
    CreatedAt = CREATED_AT;
    LastChangedBy = LAST_CHANGED_BY;
    LastChangedAt = LAST_CHANGED_AT;
    LocalLastChangedBy = LOCAL_LAST_CHANGED_BY;
    LocalLastChangedAt = LOCAL_LAST_CHANGED_AT;
  }
  association _FactoryCustOvAll { with draft; }
  validation ValidateTransportRequest on save ##NOT_ASSIGNED_TO_DETACT { create; update; delete; }
  validation ValidateDataConsistency on save { create; update; }
}

 

 

It generates a STUB Method the Class method in the class supporting the BDEF.

CheckIntfNameAndClassName FOR VALIDATE ON SAVE

IMPORTING keys FOR FactoryCustOvAll~CheckIntfNameAndClassName.

I implemented my check.  The check works as expected. I looked as similar methods when 
implementing the method.   But I must I do not fully understand the READ ENTITIES code.
But the Validation Method is working exactly as i expect it to. 
It checks the DRAFT before allowing it to be saved. 

 

 

 METHOD CheckIntfNameAndClassName.
   " Access the FactoryOverride composition (draft data )
  READ ENTITIES OF /OXO/I_FactoryCustOv_S IN LOCAL MODE
       ENTITY FactoryCustOvAll BY \_FactoryOverride
            " with SingletonID = 1, and draft data see generated CDS
       ALL FIELDS WITH VALUE #( ( SingletonID = 1  
                                  %is_draft = if_abap_behv=>mk-on  ) ) 
       RESULT DATA(lt_factory_override)
       FAILED DATA(ls_failed_child)
       REPORTED DATA(ls_reported_child).

   LOOP AT lt_factory_override ASSIGNING FIELD-SYMBOL(<ls_factory_override>).
      " The CHECK IS HERE
      data(L_Ok) =  SOME_CHECK(
              intf_name      =  <ls_factory_override>-IntfName
              class_name     = <ls_factory_override>-ClassName ).
      if l_ok = abap_true.
         continue.
      endif.
      APPEND VALUE #( %tky = <ls_factory_override>-%tky ) 
              TO failed-factoryoverride.
      APPEND VALUE #( %tky = <ls_factory_override>-%tky
             %msg = new_message( id = '/OXO/CORE_MSG'
                            number = '001'
                            v1 = <ls_factory_override>-IntfName
                            v2 = <ls_factory_override>-ClassName
                            severity = if_abap_behv_message=>severity-error )
                            %element-IntfName = if_abap_behv=>mk-on ) 
                   TO reported-factoryoverride.
            ENDLOOP.
    ENDMETHOD.

 

 




 

 

CLASS /oxo/bp_i_factorycustov_s DEFINITION  LOCAL FRIENDS ltcl.
CLASS ltcl DEFINITION FINAL FOR TESTING
  DURATION SHORT
  RISK LEVEL HARMLESS.
  PRIVATE SECTION.
    CLASS-DATA:
      cds_test_environment TYPE REF TO if_cds_test_environment,
      sql_test_environment TYPE REF TO if_osql_test_environment,
      class_under_test     TYPE REF TO lhc_/OXO/I_FACTORYCUSTOV_S.
    CLASS-METHODS:
      class_setup,
      class_teardown.
    METHODS:
      setup,
      teardown,
      test_valid_combi_cds_test FOR TESTING RAISING cx_static_check,
      test_valid_combi_entities FOR TESTING RAISING cx_static_check.

ENDCLASS.

CLASS ltcl IMPLEMENTATION.

  METHOD class_setup.

   cds_test_environment = cl_cds_test_environment=>create_for_multiple_cds(
           i_for_entities = VALUE #( ( i_for_entity = '/OXO/I_FACTORYCUSTOV_S' ) )
                             ).
" OBSERVATION cds_test_environment internally only has double for
" /oxo/factorycust and not teh draft tables .  So how can you set them ???

   cds_test_environment->enable_double_redirection(  ).

   sql_test_environment = cl_osql_test_environment=>create(
              i_dependency_list = VALUE #( ( '/OXO/D_FACTORYCU' )
                                           ( '/OXO/D_FACTORY_S' )
                                         )
                                                          ).

    CREATE OBJECT class_under_test FOR TESTING.
  ENDMETHOD.

  METHOD class_teardown.
    cds_test_environment->destroy( ).
    sql_test_environment->destroy( ).
  ENDMETHOD.

  METHOD setup.
    cds_test_environment->clear_doubles( ).
    sql_test_environment->clear_doubles( ).

  ENDMETHOD.

  METHOD teardown.
    ROLLBACK ENTITIES.
  ENDMETHOD.

  METHOD test_valid_combi_cds_test.

  " I cant get the CDS_TEST_ENVIRONMENT to work.
  " only /oxo/factorycust is generated as double.
  " the read entities never finds any data.

    DATA: lt_factorycust TYPE STANDARD TABLE OF /oxo/factorycust.
    lt_factorycust = VALUE #(   (
                    Intf_Name        = '/OXO/IF_VALID'
                    Class_Name       = '/OXO/CL_VALID'         )  ).
    cds_test_environment->insert_test_data( lt_factorycust ).

" ive tried adding the missing cds data via sql_test_environment
" this doesnt help....  The read entities in the Method under test is always empty.

    DATA: lt_d_factory_s TYPE STANDARD TABLE OF /oxo/d_factory_s.
    lt_d_factory_s = VALUE #(
      ( SingletonID = 1
        hasActiveEntity = abap_false  " This indicates it's a draft?
      )  ).
    sql_test_environment->insert_test_data( lt_d_factory_s ).

    " Prepare test data for FactoryOverride
    DATA: lt_d_factorycu TYPE STANDARD TABLE OF /oxo/d_factorycu.
    lt_d_factorycu = VALUE #(
      ( SingletonID = 1
        BusinessContext = ''
        IntfName = '/OXO/IF_VALID'
        ClassName = '/OXO/CL_VALID'
        UseSingleton = abap_false
        hasActiveEntity = abap_false  " ?? is this right ??
      ) ).

    sql_test_environment->insert_test_data( lt_d_factorycu ).

    DATA: failed   TYPE RESPONSE FOR FAILED LATE /OXO/I_FactoryCustOv_S,
          reported TYPE RESPONSE FOR REPORTED LATE /OXO/I_FactoryCustOv_S.

    class_under_test->CheckIntfNameAndClassName(
      EXPORTING
        keys = VALUE #( ( SingletonID = 1 %is_draft = if_abap_behv=>mk-on ) )
      CHANGING
        failed   = failed
        reported = reported
    ).

    " Verify the results
    cl_abap_unit_assert=>assert_initial( failed ).
    cl_abap_unit_assert=>assert_initial( reported ).

  ENDMETHOD.



  METHOD test_valid_combi_entities.

  " I CANT GET THIS TO WORK, is this even the right way ?????
  " It always returns FAILED (ls_failed)
  " so what is the correct syntax to modify the entities ?????
     MODIFY ENTITIES OF /OXO/I_FactoryCustOv_S
      ENTITY FactoryCustOvAll
      CREATE SET FIELDS WITH VALUE #(
        ( %cid = 'ROOT1'
          %is_draft = if_abap_behv=>mk-on
          "SingletonID = 1  " is read only how to pass this in, if it doesnt auto set ?
          )
      )
      CREATE BY \_FactoryOverride
      FIELDS ( BusinessContext IntfName ClassName UseSingleton )
      WITH VALUE #(
        ( %cid_ref = 'ROOT1'
          %target = VALUE #(
            ( %cid = 'CHILD1'
              BusinessContext = 'TEST_CONTEXT'
              IntfName = '/OXO/IF_VALID'
              ClassName = '/OXO/CL_VALID'
              UseSingleton = abap_false )
          )
        )
      )
    MAPPED DATA(ls_mapped)
    FAILED DATA(ls_failed)   " fail is set. Cause "not_found"
    REPORTED DATA(ls_reported).

"not point continuing here as MOFIFY ENTITIES always fails......

    " Verify that the test data was created successfully
*    cl_abap_unit_assert=>assert_initial( ls_failed ).
*    cl_abap_unit_assert=>assert_initial( ls_reported ).
*
*    " Execute the method under test
*    DATA: failed   TYPE RESPONSE FOR FAILED LATE /OXO/I_FactoryCustOv_S,
*          reported TYPE RESPONSE FOR REPORTED LATE /OXO/I_FactoryCustOv_S.
*
*    class_under_test->CheckIntfNameAndClassName(
*      EXPORTING
*        keys = VALUE #( ( SingletonID = 1 %is_draft = if_abap_behv=>mk-on ) )
*      CHANGING
*        failed   = failed
*        reported = reported
*    ).
*
*    " Verify the results
*    cl_abap_unit_assert=>assert_initial( failed-factoryoverride ).
*    cl_abap_unit_assert=>assert_initial( reported-factoryoverride ).

  ENDMETHOD.

ENDCLASS.

 

 


 So how can you unit test 
class_under_test->CheckIntfNameAndClassName 
All attempts to  mock data for the method under test call dont work.
I attached the generated view entities and the 3 tables.
The 2 draft tables are also generated.




 

Accepted Solutions (0)

Answers (0)