This is a test message to test the length of the message box.
Login
ABAP Unit OData testen
Erstellt von Software-Heroes

ABAP Unit - OData testen

523

In diesem Artikel geht es um die Testbarkeit von OData Services und wie du damit auch Schnittstellen einfach und schnell testen kannst.

Werbung


In diesem Artikel werden wir uns das Testen eines OData Service auf zwei Arten ansehen. Einmal über den klassischen Weg mit einer Data-Provider Klasse und einmal über den neuen Weg eines Service über RAP.

 

Data-Provider Klasse

Allgemein

Um eine Data-Provider Klasse testen zu können, müssen wir zuerst eine Instanz der Klasse, sowie eine Instanz des Kontext-Objekts erzeugen, um überhaupt sauber die Methode testen zu können. Hierfür sind einige Zusatzschritte nötig, damit wir den Provider sauber testen können. Dazu wollen wir dir im ersten Schritt einmal den Testfall etwas näherbringen.

Wir möchten in unserem Test einen OData Service für die folgende Tabelle zur Verfügung stellen, der die typischen CRUD Operationen zur Verfügung stellt. Die Tabelle ist mit allen möglichen Demo-Felder bestückt:

 

Das Legen wir einen Service über die Transaktion SEGW an und importieren die Tabelle als Struktur. Das System wird einen entsprechenden Vorschlag für die Namen der Felder machen. Die Entität benennen wir der Einfachheit “DATA”.

 

Die vollständige Implementierung der DPC-Klasse ZCL_TEST_UNITTEST_DPC_EXT findest du bei den entsprechenden Beispielen am Ende des Buches. Dazu nun die folgende Testklasse, um den Testfall für das Anlegen und Lesen zu implementieren.

CLASS ltc_odata DEFINITION FINAL FOR TESTING
  DURATION SHORT
  RISK LEVEL HARMLESS.

  PRIVATE SECTION.
    DATA:
      mo_cut                    TYPE REF TO zcl_test_unittest_dpc_ext,
      mo_request_context_object TYPE REF TO /iwbep/cl_mgw_request_unittst.

    METHODS:
      read_data FOR TESTING RAISING cx_static_check,
      create_data FOR TESTING RAISING cx_static_check,

      prepare_cut.
ENDCLASS.


CLASS ltc_odata IMPLEMENTATION.
  METHOD prepare_cut.
    mo_cut = NEW zcl_test_unittest_dpc_ext( ).

    DATA(ls_request_context) = VALUE /iwbep/cl_mgw_request_unittst=>ty_s_mgw_request_context_unit(
      technical_request = VALUE #(
        source_entity_set     = 'DATASet'
        target_entity_set     = 'DATASet'
        source_entity_type    = 'DATA'
        target_entity_type    = 'DATA'
      )
    ).

    mo_request_context_object = mo_cut->/iwbep/if_mgw_conv_srv_runtime~init_dp_for_unit_test( ls_request_context ).
  ENDMETHOD.


  METHOD read_data.
    DATA:
      lt_data TYPE STANDARD TABLE OF zbs_test_data.

    prepare_cut( ).

    DATA(lt_filter) = VALUE /iwbep/t_mgw_select_option(
      ( 
        property = 'CURRENCY' 
        select_options = VALUE #( ( sign = 'I' option = 'EQ' low = 'CHF' ) ) 
      )
    ).

    mo_cut->/iwbep/if_mgw_appl_srv_runtime~get_entityset(
      EXPORTING
        io_tech_request_context  = mo_request_context_object
        it_filter_select_options = lt_filter
      IMPORTING
        er_entityset             = DATA(lr_entity)
        es_response_context      = DATA(ls_response_context)
    ).

    ASSIGN lr_entity->* TO FIELD-SYMBOL(<lt_data>).
    lt_data = CORRESPONDING #( <lt_data> ).

    cl_abap_unit_assert=>assert_equals( act = lines( lt_data ) exp = 2 ).
  ENDMETHOD.


  METHOD create_data.
    DATA:
      ls_new TYPE zbs_test_data.

    prepare_cut( ).

    DATA(ls_new_data) = VALUE zbs_test_data(
      description   = 'A set of testdata from UNIT Test'
      amount        = '12.50'
      currency      = 'USD'
      creation_user = sy-uname
      creation_time = sy-uzeit
      creation_data = sy-datum
    ).
    DATA(lo_data_provider) = NEW /iwbep/cl_cp_v2_entry_provider( REF #( ls_new_data ) ).

    mo_cut->/iwbep/if_mgw_appl_srv_runtime~create_entity(
      EXPORTING
        io_data_provider        = lo_data_provider
        io_tech_request_context = mo_request_context_object
      IMPORTING
        er_entity               = DATA(lr_entity)
    ).

    ASSIGN lr_entity->* TO FIELD-SYMBOL(<ls_data>).
    ls_new = CORRESPONDING #( <ls_data> ).

    cl_abap_unit_assert=>assert_not_initial( ls_new-identifier ).
  ENDMETHOD.
ENDCLASS.

 

Ablauf

Wie sieht es nun mit dem eigentlichen Testfall und der Ausführung aus? Für den Aufbau der Testinstanz müssen einige Schritte vorher ausgeführt werden, da wir auch noch ein Kontext Objekt benötigen, um die Methoden ausführen zu können.

  • Vorbereitung
    • Kontext-Struktur befüllen mit zu testender Entität und dem Namen des Sets
    • Init-Methode der Service-Runtime aufrufen
    • Sichern des Kontext-Objekts in der Testklasse
  • Lesen von Daten
    • Definition eines Filters zur Einschränkung der Datensätze
    • Aufruf der Methode GET_ENTITYSET mit Kontext Objekt und Zusatzdaten (Filter)
    • Prüfung der gefundenen Datensätze für den Test
  • Anlegen von Daten
    • Vorbereitung eines neuen Datensatzes
    • Erstellung eines Datenprovider-Objekts mit den Daten als Referenz
    • Aufruf der Methode CREATE_ENTITY mit Kontext Objekt und Datenprovider
    • Prüfung des neuen Schlüssels für den Test

 

Hinweis: Das Testen von OData Services über diese Methode wird von uns nur teilweise empfohlen, da die Methodik nicht den vollen Funktionsumfang der Services unterstützt. Wenn möglich, sollte auf das Testen mit Service Bindings zurückgegriffen werden.

 

Service Binding

Das Service Bindung ist die neueste Variante einen OData zur Verfügung zu stellen und zwar aus der Implementierung eines Business Objekt über RAP. Dabei stellt Eclipse einen Wizard zur Verfügung der das Coding in einer eigenen Testklasse implementiert oder du schreibst dir deine Tests selbst. Wir möchten dir an dieser Stelle nicht zeigen, wie du per RAP ein eigenes Business Objekt aufbaust, aber wie du aus dem fertigen Service eine Testklasse generierst und diese dann testest. RAP für sich, würde auch wieder ein halbes Buch befüllen.

 

Vorbereitung

Um die Testklasse automatisch über den Wizard anlegen zu können, musst du das Service-Bindung des Datenmodells öffnen, für die du deine Testfälle definieren möchtest. Das Objekt erstellt für einen Service den entsprechenden Endpunkt und das Protokoll (in diesem Fall OData v2) zur Verfügung.

 

Mit einem Rechtsklick auf die entsprechende Entität kannst du dann über das Kontextmenü ein Testklasse generieren.

 

Im Wizard musst du dann nur noch das Paket und den Namen der Testklasse hinterlegen, der Rest wird automatisch vorbelegt. Am Ende wird eine globale Testklasse angelegt, während die eigentlichen Testfälle wieder in den lokalen Testklassen dieser Klasse liegen.

 

Beispiel

Wie schon beim anderen OData-Service implementieren wir beispielhaft für dich den Fall für das Lesen von Datensätzen und die Anlage eines neuen Datensatzes. Die Handhabung des lokalen Proxys ist um einiges einfacher, als das Arbeiten über die DPC Klasse. Für den Proxy gibt es jeweils eine Version für On-Premise und eine für die BTP, je nachdem auf welcher Umgebung du unterwegs bist.

CLASS ltc_odata_service DEFINITION FINAL FOR TESTING
  DURATION SHORT
  RISK LEVEL HARMLESS.

  PRIVATE SECTION.
    DATA:
      mo_client_proxy TYPE REF TO /iwbep/if_cp_client_proxy.

    METHODS:
      setup RAISING cx_static_check,

      create_data FOR TESTING RAISING cx_static_check,
      read_data FOR TESTING RAISING cx_static_check.
ENDCLASS.

CLASS ltc_odata_service IMPLEMENTATION.
  METHOD setup.
    " On-Premise Proxy
    mo_client_proxy = /iwbep/cl_cp_client_proxy_fact=>create_v2_local_proxy(
      VALUE #( service_id = 'ZBS_UI_DEMOSIMPLERAP_O2' service_version = '0001' )
    ).

    " BTP Proxy
*    mo_client_proxy = cl_web_odata_client_factory=>create_v2_local_proxy(
*      VALUE #( service_id = 'ZBS_UI_DEMOSIMPLERAP_O2' service_version = '0001' )
*    ).
  ENDMETHOD.


  METHOD create_data.
    DATA:
      ls_business_data TYPE ZBS_C_DemoSimpleRAP,
      lo_request       TYPE REF TO /iwbep/if_cp_request_create,
      lo_response      TYPE REF TO /iwbep/if_cp_response_create.

    ls_business_data = VALUE #(
      Item        = 'HAMMER'
      Description = 'A good tool for nails'
      ItemNumber  = 4911
    ).

    lo_request = mo_client_proxy->create_resource_for_entity_set( 'SimpleRap' )->create_request_for_create( ).
    lo_request->set_business_data( ls_business_data ).
    lo_response = lo_request->execute( ).

    CLEAR ls_business_data.
    lo_response->get_business_data( IMPORTING es_business_data = ls_business_data ).

    cl_abap_unit_assert=>assert_not_initial( ls_business_data-UniqueKey ).
  ENDMETHOD.


  METHOD read_data.
    DATA:
      lt_business_data  TYPE TABLE OF ZBS_C_DemoSimpleRAP,
      lo_request        TYPE REF TO /iwbep/if_cp_request_read_list,
      lo_response       TYPE REF TO /iwbep/if_cp_response_read_lst,
      lo_filter_factory TYPE REF TO /iwbep/if_cp_filter_factory,
      lt_r_number       TYPE RANGE OF ZBS_C_DemoSimpleRAP-ItemNumber.

    lo_request = mo_client_proxy->create_resource_for_entity_set( 'SimpleRap' )->create_request_for_read( ).

    lt_r_number = VALUE #( ( sign = 'I' option = 'EQ' low = 2 ) ).

    lo_filter_factory = lo_request->create_filter_factory( ).
    DATA(lo_filter_node) = lo_filter_factory->create_by_range(
      iv_property_path     = 'ITEMNUMBER'
      it_range             = lt_r_number ).
    lo_request->set_filter( lo_filter_node ).

    lo_request->set_top( 50 )->set_skip( 0 ).
    lo_response = lo_request->execute( ).

    lo_response->get_business_data( IMPORTING et_business_data = lt_business_data ).

    cl_abap_unit_assert=>assert_equals( act = lines( lt_business_data ) exp = 2 ).
  ENDMETHOD.
ENDCLASS.

 

Für die Zuweisung der Daten verwenden wir den Consumption View (Core Data Service), da hier die entsprechenden Feldnamen für den OData Service bereitgestellt werden und für die Datenbank andere Feldnamen gelten könnten.

 

Ablauf

Den entsprechenden Ablauf in der Testklasse noch einmal kurz erklärt:

  • Vorbereitung
    • Erstellung des lokalen Proxy Objekts für die Verbindung zum Service
  • Lesen von Daten
    • Erzeugen des Request Objekts zum Lesen
    • Setzen des Filters und TOP/SKIP Werte
    • Ausführen des Requests
    • Lesen der Daten aus dem Response Objekt
  • Anlegen von Daten
    • Erzeugen des neuen Datensatzes
    • Erzeugen des Request Objekts zur Anlage 
    • Übergabe der Daten
    • Ausführen des Requests
    • Auswerten der Antwort (Befüllung des Schlüssels)

 

Test Double

Du möchtest nicht gegen die echten Daten in der Datenbank testen? Dann kannst du auch einen Test Double für den Core Data Service verwenden, der angesprochen wird. Der SQL Double für die Tabelle wird hier nicht funktionieren. 

Dazu einfach in der Setup Methode das entsprechende Double vorbereiten und aktivieren. Die Zugriffe über den Proxy laufen dann gegen den CDS Double.

 

Fazit

OData Services können genau so wie andere Objekte getestet und geprüft werden, was deine Entwicklung in Zukunft stabiler machen sollte. Die Bereitstellung und Weiterentwicklung solcher Services wird in Zukunft einen großen Teil der Ressourcen ausmachen, die im Backend benötigt werden.


Enthaltene Themen:
ABAP UnitABAPUnit TestsOData testen
Kommentare (0)



Und weiter ...

Bist du zufrieden mit dem Inhalt des Artikels? Wir posten jeden Freitag neuen Content im Bereich ABAP und unregelmäßig in allen anderen Bereichen. Schaue bei unseren Tools und Apps vorbei, diese stellen wir kostenlos zur Verfügung.


ABAP Unit - Testausführung

Kategorie - ABAP

Welche Möglichkeiten gibt es zur Ausführung von ABAP Unit und welche versteckten Funktionen kennst du vielleicht noch nicht? Mehr Details zu den verschiedenen Modi in diesem Artikel.

25.06.2024

ABAP Unit - Automatisierung

Kategorie - ABAP

Wann gehen in der Entwicklung Objekte kaputt und welche Seiteneffekte können Anpassungen haben? In diesem Artikel schauen wir uns das Thema einmal näher an.

05.01.2024

ABAP Unit - TDF (Function Double)

Kategorie - ABAP

Schauen wir uns in diesem Artikel einmal an, wie wir mit Funktionsbausteinen als Abhängigkeit umgehen können, ohne diese mitzutesten.

07.04.2023

RAP - ABAP Unit (Service)

Kategorie - ABAP

Wie testet man den Service einer Schnittstelle oder RAP App eigentlich automatisch? In diesem Artikel schauen wir uns Unit Tests für OData Services an.

20.01.2023

RAP - ABAP Unit (Business Objekt)

Kategorie - ABAP

An dieser Stelle schauen wir uns einmal an, wie wir unser RAP Business Objekt automatisch testen können, um so alle wichtigen Funktionen per Knopfdruck zu prüfen.

13.01.2023