oSQL Test Environment

Related Post

  • No related post.

Unit Tests werden immer wichtiger. Je mehr ich sie selber verwende, desto mehr merke ich aber auch, wie schwierig es teilweise ist, vernünftige Unit Tests aufzubauen und sinnvoll zu testen. Seit ABAP Release 7.52 gibt es eine neue Möglichkeit, Daten für nit Tests zu “fälschen”: Das Open SQL Test Environment.

Mit diesem Framework ist es sehr einfach, der Datenbank manipulierte Daten unterzuschieben. Wie das im Detail geht, zeige ich dir hier.

Ausgangslage

Stellen wir uns vor, wir haben eine Anwendung, die zu einem Material die Materialart ermitteln soll und anhand der Materialart prüfen soll, ob eine bestimmte Aktion erlaubt ist oder nicht.

Die Klasse zur Ermittlung der Materialstammdaten könnte folgendermaßen aussehen:

CLASS mat DEFINITION.
  PUBLIC SECTION.
    METHODS check_usage
      IMPORTING
        matnr TYPE matnr
      RETURNING
        VALUE(result) TYPE abap_bool.
      
  PRIVATE SECTION.
    METHODS get_type
      IMPORTING
        matnr TYPE matnr
      RETURNING
        VALUE(mtart) TYPE mtart.
ENDCLASS.
CLASS mat IMPLEMENTATION.
  METHOD check_usage.
    IF get_type( matnr ) = 'FERT'.
      result = abap_true.
    ENDIF. 
  ENDMETHOD.

  METHOD get_type.
    SELECT SINGLE mtart FROM mara INTO mtart WHERE matnr = matnr.
  ENDMETHOD.
ENDCLASS.

Mit der Methode CHECK_USAGE kann ich ermitteln, ob ein gegebenes Material für irgendeine hier nicht näher definierte Verwendung erlaubt ist oder nicht.

Unit Tests

Wenn ich im Test System zwei Materialien habe, mit denen ich das testen kann, dann könnten die Unit Tests folgendermaßen aussehen:

CLASS test DEFINITION FOR TESTING
  DURATION SHORT
  RISK LEVEL HARMLESS.
  PRIVATE SECTION.

    DATA f_cut TYPE REF TO mat.
    METHODS: setup.
    METHODS: check_allowed FOR TESTING.
    METHODS: check_forbidden FOR TESTING.
ENDCLASS. 

CLASS test IMPLEMENTATION.

  METHOD setup.
    f_cut = NEW #( ).
  ENDMETHOD.

  METHOD check_allowed.
    cl_abap_unit_assert=>assert_equals(
      act   = f_cut->check_usage( 'MAT-2277' )
      exp   = abap_true ).
  ENDMETHOD.

  METHOD check_forbidden.
    cl_abap_unit_assert=>assert_equals(
      act   = f_cut->check_usage( 'MAT-565' )
      exp   = abap_false ).
  ENDMETHOD.

ENDCLASS.

Demzufolge ist das auf der Datenbank vorhandene Material MAT-2277 ein Material vom Typ “FERT” und das Material MAT-565 hat einen anderen Typ.

Problem Stammdaten

Auf Stammdaten darf man sich allerdings nicht verlassen. Diese werden – gerade in einem Entwicklungssystem – gerne mal geändert oder gelöscht. Bei einem Unit Test muss ich mich jedoch auf die Daten verlassen können. Das kann ich nur, wenn ich diese fest mitgebe.

oSQL Test Framework

Mit dem oSQL Test Environment kann ich das sehr komfortabel tun. Und zwar folgendermaßen:

Es muss mit der Methode CL_OSQL_TEST_ENVIRONMENT=>CREATE eine Instanz erstellt werden. Dieser Instanz gebe ich die Tabellennamen mit, die ich beeinflussen möchte. Zusätzlich gebe ich genau die Daten mit, die der Datenbank vorgegaukelt werden sollen. In diesem Beispiel verwende ich das Material FAKEMAT1 als Testmaterial für FERT und FAKEMAT2 als Testmaterial für ein Material ungleich FERT.

CLASS test DEFINITION FOR TESTING
  DURATION SHORT
  RISK LEVEL HARMLESS.
  PRIVATE SECTION.
    CLASS-DATA: osql TYPE REF TO if_osql_test_environment.
    CLASS-METHODS: class_setup.
    CLASS-METHODS: class_teardown.
    DATA f_cut TYPE REF TO mat.
    METHODS: setup.
    METHODS: check_allowed FOR TESTING.
    METHODS: check_forbidden FOR TESTING.
ENDCLASS.     

CLASS test IMPLEMENTATION.

  METHOD class_setup.
    osql = cl_osql_test_environment=>create( VALUE #( ( 'MARA' ) ) ).
    DATA(materials) = VALUE mara_tab( 
      ( mandt = '100' matnr = 'FAKEMAT1' mtart = 'FERT' )
      ( mandt = '100' matnr = 'FAKEMAT2' mtart = 'HALB' ) ).
    osql->insert_test_data( materials ).
  ENDMETHOD.

  METHOD class_teardown.
    osql->destroy( ).
  ENDMETHOD.

  METHOD setup.
    f_cut = NEW #( ).
  ENDMETHOD.

  METHOD check_allowed.
    cl_abap_unit_assert=>assert_equals(
      act   = f_cut->check_usage( 'FAKEMAT1' )
      exp   = abap_true ).
  ENDMETHOD.

  METHOD check_forbidden.
    cl_abap_unit_assert=>assert_equals(
      act   = f_cut->check_usage( 'FAKEMAT2' )
      exp   = abap_false ).
  ENDMETHOD.

ENDCLASS.

Verwendung

Die Anwendung ist wirklich denkbar einfach. Keine Ahnung, was da im Hintergrund passiert, aber das ist mir (zur Zeit) auch egal. Hauptsache, es funktioniert.

Das Gute ist, dass es auch mit Funktionsbausteinen funktioniert, die innerhalb der Testumgebung aufgerufen werden.

Wenn du ermitteln möchtest, welche Tabellen angesprochen werden, dann kannst du dies einigermaßen bequem mit der Transaktion SAT machen. Dort werden alle Datenbankzugriffe aufgeführt.

Enno Wulff
Letzte Artikel von Enno Wulff (Alle anzeigen)