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

ABAP unit test for updating a database table successfully

Former Member
2,732

I am working on ABAP unit test. There is a method that imports some parameters and then update a database table. how can I test whether the update of this method is successful? Thank you!

1 ACCEPTED SOLUTION
Read only

matt
Active Contributor
0 Likes
1,620

On 7.5x (where x = 2, I think), there's a way of telling the kernel this is a test, and instead of writing to the actual database, it reads and writes to an area of memory (entirely transparently to you) instead.

Before then:

I create a local interface lif_db_accessor. I define methods that mirror the sql statements. So for

SELECT field1 field2 FROM table INTO some_Structure WHERE field3 = some_value and field4 = some_other_value,

I have a method:

METHOD get_stuff
IMPORTING i_field1 TYPE ... i_field2 TYPE... i_field3 TYPE ... i_field 4 TYPE ...
RETURNING (VALUE) r_something TYPE some_structure.

Then I implement lif_db_accessor in a local class lcl_db_accessor with the actual SQL.

For my main class, I define

CLASS-DATA _db_accessor TYPE REF TO lif_db_accessor.

You'll need somewhere (look it up)

INTERFACE lif_db_accessor DEFERRED.

in the class_constructor I have a statement.

_db_accessor = new zcl_db_accessor( ).

Now, you need to make your ltc_test_main test class a LOCAL FRIEND of your main class.

Create a test double ltd_db_accessor that implement lif_db_accessor. Here, you implement all the methods of the interface, but instead of to a db table, to an internal table. So if it was MARA, you'd have something like.

CLASS ltd_db_accessor DEFINITION.
PUBLIC SECTION.
  INTERFACE lif_db_accessor.
  DATA db TYPE HASHED TABLE OF mara WITH UNIQUE KEY matnr.ENDCLASS.

CLASS ltd_db_accessor IMPLEMENTATION.
  METHOD lif_db_accessor~get_mtart.
    " SELECT SINGLE mtart FROM MARA INTO r_mtart WHERE matnr EQ i_matnr.
    READ TABLE db INTO data(db_Record) WITH TABLE KEY matnr = i_matnr.
    r_mtart = db_Record-mtart.
  ENDMETHOD.
ENDCLASS.

In the definition of your test class you have

DATA:
  cut TYPE REF TO main class.
  db TYPE REF TO ltd_db_accessor.

In the setup method you have

me->cut = new #( ).
me->db = new #( ).
me->cut->_db_accessor = me->db.
me->db = value #( ...db values... ).

Now, whenever your code under test use the db accessor, instead of using lcl_db_accessor and getting data from the database, it will get the data from your ltd_db_accessor db attribute.

I'm preparing a blog on this very subject as I've been doing the above rather a lot recently.

On 7.5x (where x = 2, I think), there's a way of telling the kernel this is a test, and instead of writing to the actual database, it reads and writes to an area of memory (entirely transparently to you) instead.

Before then:

I create a local interface lif_db_accessor. I define methods that mirror the sql statements. So for

SELECT field1 field2 FROM table INTO some_Structure WHERE field3 = some_value and field4 = some_other_value,

I have a method:

METHOD get_stuff
IMPORTING i_field1 TYPE ... i_field2 TYPE... i_field3 TYPE ... i_field 4 TYPE ...
RETURNING (VALUE) r_something TYPE some_structure.

Then I implement lif_db_accessor in a local class lcl_db_accessor with the actual SQL.

For my main class, I define

CLASS-DATA _db_accessor TYPE REF TO lif_db_accessor.

You'll need somewhere (look it up)

INTERFACE lif_db_accessor DEFERRED.

in the class_constructor I have a statement.

_db_accessor = new zcl_db_accessor( ).

Now, you need to make your ltc_test_main test class a LOCAL FRIEND of your main class.

Create a test double ltd_db_accessor that implement lif_db_accessor. Here, you implement all the methods of the interface, but instead of to a db table, to an internal table. So if it was MARA, you'd have something like.

CLASS ltd_db_accessor DEFINITION.
PUBLIC SECTION.
  INTERFACE lif_db_accessor.
  DATA db TYPE HASHED TABLE OF mara WITH UNIQUE KEY matnr.ENDCLASS.

CLASS ltd_db_accessor IMPLEMENTATION.
  METHOD lif_db_accessor~get_mtart.
    " SELECT SINGLE mtart FROM MARA INTO r_mtart WHERE matnr EQ i_matnr.
    READ TABLE db INTO data(db_Record) WITH TABLE KEY matnr = i_matnr.
    r_mtart = db_Record-mtart.
  ENDMETHOD.
ENDCLASS.

In the definition of your test class you have

DATA:
  cut TYPE REF TO main class.
  db TYPE REF TO ltd_db_accessor.

In the setup method you have

me->cut = new #( ).
me->db = new #( ).
me->cut->_db_accessor = me->db.
me->db = value #( ...db values... ).

Now, whenever your code under test use the db accessor, instead of using lcl_db_accessor and getting data from the database, it will get the data from your ltd_db_accessor db attribute.

I'm preparing a blog on this very subject as I've been doing the above rather a lot recently.

2 REPLIES 2
Read only

matt
Active Contributor
0 Likes
1,621

On 7.5x (where x = 2, I think), there's a way of telling the kernel this is a test, and instead of writing to the actual database, it reads and writes to an area of memory (entirely transparently to you) instead.

Before then:

I create a local interface lif_db_accessor. I define methods that mirror the sql statements. So for

SELECT field1 field2 FROM table INTO some_Structure WHERE field3 = some_value and field4 = some_other_value,

I have a method:

METHOD get_stuff
IMPORTING i_field1 TYPE ... i_field2 TYPE... i_field3 TYPE ... i_field 4 TYPE ...
RETURNING (VALUE) r_something TYPE some_structure.

Then I implement lif_db_accessor in a local class lcl_db_accessor with the actual SQL.

For my main class, I define

CLASS-DATA _db_accessor TYPE REF TO lif_db_accessor.

You'll need somewhere (look it up)

INTERFACE lif_db_accessor DEFERRED.

in the class_constructor I have a statement.

_db_accessor = new zcl_db_accessor( ).

Now, you need to make your ltc_test_main test class a LOCAL FRIEND of your main class.

Create a test double ltd_db_accessor that implement lif_db_accessor. Here, you implement all the methods of the interface, but instead of to a db table, to an internal table. So if it was MARA, you'd have something like.

CLASS ltd_db_accessor DEFINITION.
PUBLIC SECTION.
  INTERFACE lif_db_accessor.
  DATA db TYPE HASHED TABLE OF mara WITH UNIQUE KEY matnr.ENDCLASS.

CLASS ltd_db_accessor IMPLEMENTATION.
  METHOD lif_db_accessor~get_mtart.
    " SELECT SINGLE mtart FROM MARA INTO r_mtart WHERE matnr EQ i_matnr.
    READ TABLE db INTO data(db_Record) WITH TABLE KEY matnr = i_matnr.
    r_mtart = db_Record-mtart.
  ENDMETHOD.
ENDCLASS.

In the definition of your test class you have

DATA:
  cut TYPE REF TO main class.
  db TYPE REF TO ltd_db_accessor.

In the setup method you have

me->cut = new #( ).
me->db = new #( ).
me->cut->_db_accessor = me->db.
me->db = value #( ...db values... ).

Now, whenever your code under test use the db accessor, instead of using lcl_db_accessor and getting data from the database, it will get the data from your ltd_db_accessor db attribute.

I'm preparing a blog on this very subject as I've been doing the above rather a lot recently.

Read only

Sandra_Rossi
Active Contributor
1,620

What is your ABAP release? (from 7.52 there is the Open SQL Test Double Framework)