Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
wilbert_sison2
Active Participant

SAP has been doing some really good work upgrading its  tools.  We  have recently upgraded to SAP_ABAP 740. I'm an advocate of ABAP Unit testing and this upgrade gave me the opportunity to try an example on the new Test Double Framework.   Prajul Meyana's  ABAP Test Double Framework - An Introduction says that the new framework is available from SP9. We're in SP8, but I can't wait to tesdrive this.  So I started poking around. One of my colleagues pointed out that CL_ABAP_TESTDOUBLE is delivered with the release.  YEY!


Below is an example of behavior verification using the framework and it appears to work. Maybe later, I'll make a much simpler cut. At this stage I just wanted to run it through a real life example within our code base.

Below is my application code. It's a simple custom service implementation to create Chart of Authority records for Opentext Vendor Invoice Management.   ( It's not relevant here but note that we use FEH to manage exceptions for enterprise service errors.  Maybe I can show a test of that exception in a later blog. )

Further below is one  of my test classes with one of the test methods implemented.

The test double framework does three important things in this example .

  • It sets the behavior of get_manager_id( ) for when the test is executed.
  • It sets the expected invocation parameters of set_coa_details( )
  • The verify_expectation( )  verifies that the set_coa_details( ) within the Service interface has been invoked as expected.

I use a factory implementation to inject test doubles. Some of you don't like it. I understand that. Hope that doesn't distract from the intent. Have fun. As I mentioned when my colleague Custodio de Oliveira pointed it out that it's available, "Let's break it".

App Code

  METHOD ZIF_FEH~PROCESS.

    DATA:

      lo_coa_user            TYPE REF TO zif_opentext_vim_coa_user,

      lo_cx_opentext         TYPE REF TO zcx_opentext_service,

      lo_cx_coa_user         TYPE REF TO zcx_opentext_service,

      ls_main_error          TYPE bapiret2,

      lt_coa_details         TYPE zopentext_coa_details_tt,

      ls_coa_details         TYPE LINE OF zopentext_coa_details_tt,

      lv_manager_id          TYPE /ors/umoid,

      lv_max_counter         TYPE /opt/counter.

    FIELD-SYMBOLS:

      <ls_process_coa_details>      TYPE LINE OF zopentext_coa_detl_process_tt.

    me->_s_process_data = is_process_data.

    TRY.

        TRY.

            lo_coa_user      = zcl_vim_coa_user_factory=>get_instance( )->get_coa_user( iv_windows_id = _s_process_data-windows_id

                                                                                        iv_active_users_only = abap_false ).

            lv_manager_id    = lo_coa_user->get_manager_id( ).

          CATCH zcx_opentext_service INTO lo_cx_coa_user.

            CLEAR lv_manager_id.

        ENDTRY.


        LOOP AT _s_process_data-coa_details[]

          ASSIGNING <ls_process_coa_details>

          WHERE start_date <= sy-datum

          AND   end_date   >= sy-datum" Record removed in ECC if not in validity date

          ADD 1 TO lv_max_counter.

          ls_coa_details-counter        = lv_max_counter.

          ls_coa_details-expense_type   = <ls_process_coa_details>-expense_type.

          ls_coa_details-approval_limit = <ls_process_coa_details>-approval_limit.

          ls_coa_details-currency       = <ls_process_coa_details>-currency.

          ls_coa_details-bukrs          = '*'. " Functional requirement in ECC to set CoCode to *. Assumption : From corp - 1 user = 1 co code

          ls_coa_details-kostl          = '*'.

          ls_coa_details-internal_order = '*'.

          ls_coa_details-wbs_element    = '*'.

          ls_coa_details-manager_id     = lv_manager_id"For new entries, Manager Id is the same as that on existing COA entries for the user.

          APPEND ls_coa_details TO lt_coa_details.

        ENDLOOP.

        " Ignore the message

        IF ( lo_cx_coa_user IS NOT INITIAL or lo_coa_user->is_deleted( ) )     " The user is deleted or does not exist

           AND lt_coa_details IS INITIAL.                                      " AND All the inbound records are deletions

          RETURN. " Ignore transaction - finish ok.

        ENDIF.

        " Raise missing user

        IF lo_cx_coa_user IS NOT INITIAL.

          RAISE EXCEPTION lo_cx_coa_user.

        ENDIF.

        " Updates

        IF lo_coa_user->is_deleted( ).

          " User &1 is deleted. COA cannot be updated.

          ""****  ZCX_FEH EXCEPTION RAISED HERE *****

        ENDIF.

        lo_coa_user->set_coa_details( lt_coa_details[] ).

        lo_coa_user->save( ).

      CATCH zcx_opentext_service INTO lo_cx_opentext.

        "****  ZCX_FEH EXCEPTION RAISED HERE *****

    ENDTRY.

  ENDMETHOD.



Local Test Class

CLASS ltc_process DEFINITION FOR TESTING

  DURATION SHORT

  RISK LEVEL HARMLESS

  FINAL.

  PRIVATE SECTION.

    METHODS: setup.

    METHODS: test_2auth                        FOR TESTING.

*    METHODS: test_2auth_1obsolete              FOR TESTING.

*    METHODS: test_missinguser_coadeletions     FOR TESTING.

*    METHODS: test_update_on_deleted_user       FOR TESTING.

*    METHODS: test_opentext_error               FOR TESTING.

    DATA : mo_coa_user TYPE REF TO zif_opentext_vim_coa_user.

    CLASS-DATA : mo_coa_user_factory TYPE REF TO zif_vim_coa_user_factory.

    DATA : mo_si_opentext_delegauth_bulk TYPE REF TO ycl_si_opentext_coa.

ENDCLASS.

CLASS ltc_process  IMPLEMENTATION.

  METHOD setup.

    mo_si_opentext_delegauth_bulk ?= ycl_si_opentext_coa=>s_create( iv_context = zcl_feh_framework=>gc_context_external ).

  ENDMETHOD.

  METHOD test_2auth .

*----------------------------------------------------------------------*

*  This tests the scenario where the user has 2 authority records      *

*  and both are saved properly.                                        *

*----------------------------------------------------------------------*

    DATA ls_process_data               TYPE zopentext_deleg_auth_process_s.

    DATA ls_coa_details_process        TYPE zopentext_coa_detl_process_s.

    DATA lt_coa_details                TYPE zopentext_coa_details_tt.

    DATA ls_coa_details                TYPE LINE OF zopentext_coa_details_tt.

         "config the test double call to manager id

    mo_coa_user ?=  cl_abap_testdouble=>create( 'ZIF_OPENTEXT_VIM_COA_USER' ).  

    cl_abap_testdouble=>configure_call( mo_coa_user )->returning( 'WILLIA60' ).

    mo_coa_user->get_manager_id( ).

    " expected results

    ls_coa_details-counter        = 1.

    ls_coa_details-currency       = 'NZD'.

    ls_coa_details-approval_limit = 200.

    ls_coa_details-expense_type   = 'CP'.

    ls_coa_details-bukrs          = '*'.

    ls_coa_details-kostl          = '*'.

    ls_coa_details-internal_order = '*'.

    ls_coa_details-wbs_element    = '*'.

    ls_coa_details-manager_id     = 'WILLIA60'.

    APPEND ls_coa_details TO lt_coa_details.

    ls_coa_details-counter        = 2.

    ls_coa_details-currency       = 'NZD'.

    ls_coa_details-approval_limit = 300.

    ls_coa_details-expense_type   = 'SR'.

    ls_coa_details-bukrs          = '*'.

    ls_coa_details-kostl          = '*'.

    ls_coa_details-internal_order = '*'.

    ls_coa_details-wbs_element    = '*'.

    ls_coa_details-manager_id     = 'WILLIA60'.

    APPEND ls_coa_details TO lt_coa_details.

         "configure the expected behavior of the set_coa_details( )

    cl_abap_testdouble=>configure_call( mo_coa_user )->and_expect( )->is_called_times( 1 ).

    mo_coa_user->set_coa_details( lt_coa_details ).

        " Inject the test double into the factory which will be used inside the  method under test.

    TRY.

        zcl_vim_coa_user_factory=>get_instance( )->set_coa_user( mo_coa_user ).

      CATCH zcx_opentext_service ##no_handler.

    ENDTRY.

    " SETUP - INPUTS To the Method under test

    ls_process_data-windows_id = 'COAUSER'.

     

    ls_coa_details_process-currency   = 'NZD'.

    ls_coa_details_process-approval_limit = 200.

    ls_coa_details_process-expense_type   = 'CP'.

    ls_coa_details_process-bukrs          = '1253'.

    ls_coa_details_process-start_date     = '20060328'.

    ls_coa_details_process-end_date       = '29990328'.

    APPEND ls_coa_details_process TO ls_process_data-coa_details.

    ls_coa_details_process-currency   = 'NZD'.

    ls_coa_details_process-approval_limit = 300.

    ls_coa_details_process-expense_type   = 'SR'.

    ls_coa_details_process-bukrs          = '1253'.

    ls_coa_details_process-start_date     = '20060328'.

    ls_coa_details_process-end_date       = '29990328'.

    APPEND ls_coa_details_process TO ls_process_data-coa_details.

    " EXECUTE the method under test

    TRY.

        mo_si_opentext_delegauth_bulk->zif_feh~process( is_process_data = ls_process_data ).

      CATCH zcx_feh  ##no_handler.

    ENDTRY.

    " Verify interactions on test double

    cl_abap_testdouble=>verify_expectations( mo_coa_user ).

  ENDMETHOD.

ENDCLASS.

Some Test Tools available in SAP_ABA 740

Test Summary - 1 test method successful

Test Coverage - only 1 test >> so it's pretty poor

Test Coverage - lots of  untested code in red!

(Sorry for the eclipse fans. I re-flashed my PC to 64 bit. I haven't had the chance to re-install my Eclipse tools. Those coverage tools are there too! ).