Skip to Content

Mocking DAOs with ABAP Test Double Framework


In this document I will show how the ABAP Test Double framework can be used to mock daos and enhance flexible and fast implemented unit tests.

For an introduction to the framework I would recommend ABAP Test Double Framework – An Introduction. and for the usage of daos and dependency injection the following blog: ABAP Unit Tests without database dependency – DAO concept.

The sample below is very basic and no real business logic is included because it focuses on the concepts. For the dependency injection of the daos I used an interface for two reasons. First when more complicated or variants of Daos are needed the interface provides more flexibilty and the ABAP test double framework currently only can mock interfaces.

If you have suggestions, hints or question feel free to comment this document as I am keen on improve my concept, since it will not be the last time I have to write a Dao 🙂

Before starting I want to highlight that this does only focus on the integration of the ABAP test double framework into Dao related testing but does not highlight the extended features the test double provides to enhance your unit tests, like eg. method call verification for methods without return parameters or exception assertion which makes the ABAP test double framework to a very useful tool.


Lets assume we need a class which should get and set information of material data. Lets call it ZCL_MATERIAL_FACADE (because it will represent the facade pattern). For simplicity reason it will only contain one method – get the grossweight for a material by providing a material number.

The access to the database should be hidden behind this class and not contain any business logic – the Material Dao.

For testing we should be independent of the current database state and there should be no need to change productive code. This is accomplished by using a mock or testdouble which is injected into the production code.

Independent testing by mocking dependent objects.png


There are different approaches to build this set of classes. I assume the simplest is to start with the DAO, continue with the material facade and finally with the mocking classes and unit tests even though tihs does not correlate with the TDD approach.

The DAO in our simplyfied example has one method get which returns one material represented by an row of the database table MARA. The concrete DAO class implements the DAO interface which contains also only one specification for the method get. Important is that the DAO contains a static instance variable which will later be used for injecting the test double (see appendix 1 and 2).

The material facade is quite straightforward (see apendix 3). Only one method getGrossWeight which gets the data over the material DAO interface.

The test double is created over the method cl_aba_testdouble, which needs as parameter an interface – in our example ZIF_MATERIAL_DAO (a class here is not permitted. The methods are configured with the method configure_call and  the subsequent call of the method to be stubbed. (see appendix 4).

The exact behavior of the test double in respect to method call and response can be configured on different ways. In the below approach the local class lclAnswerMaterialDaoGet contains this logic (for example the different return grosssweight values for the various materials). To the method stub this local class can be assigned with the method set_answer() (see appendix 5).

The final step to get the business logic tested without database dependencies is shown in the unit test at the end of the appendix. This is done with the following steps:

  1. The key step is to first create the testdouble and injected to the MaterialDao. As the MaterialDao contains only one instance (singleton pattern) which is accessed from each caller and only instantiate once from now each call on the material dao in the session is done on the material dao test double.
  2. The second step is to create the material facade and perform the desired tests. It is essential to crate the material facade after the testdoube injection into the material dao, because otherwise the material facade would create the real material dao like in productive environment.

My personal experience with the ABAP test double framework is that the first steps are not easy, especially because you have no possibility to try it out with concrete classes only.

But after a short time you get the invested time back as you have a huge amount of necessary features for testing which are integrated in the ABAP test double framework.

Feel free to share your experience and thougts.

Appendix Listing of all needed interfaces and classes

1. ZIF_DAO_MATERIAL – Common Interface for Material DAO, Mock and TestDouble

  public .
  methods GET
      value(PMARA) type MARA .

2. ZCL_DAO_MATERIAL – A simple Dao to access data of a material

class ZCL_DAO_MATERIAL definition
  create public .
public section.
  interfaces ZIF_DAO_MATERIAL .
  class-methods GETINSTANCE
      value(PINSTANCE) type ref to ZIF_DAO_MATERIAL .
  class-methods SETINSTANCE
      !PINSTANCE type ref to ZIF_DAO_MATERIAL.
protected section.
private section.
       instance type ref to ZIF_DAO_MATERIAL,
       instanceObj type ref to ZCL_DAO_MATERIAL.
    method GETINSTANCE.
       if ( instance IS INITIAL ).
          CREATE OBJECT instanceObj.
          instance ?= instanceObj.
       pInstance = instance.
    method SETINSTANCE.
       instance = pInstance.
          SELECT *
            INTO @pMARA
            FROM MARA
           WHERE matnr = @pMaterialnumber.

3. ZCL_MATERIAL_FACADE – A simple common facade for accessing material specific data

class ZCL_MATERIAL_FACADE definition
  create public .
public section.
       getGrossWeight importing pMaterialnumber type MATNR
                 returning value(pGrossWeight) type BRGEW.
protected section.
private section.
   DATA: materialDao type ref to ZIF_DAO_MATERIAL.
       method constructor.
          materialDao = ZCL_DAO_MATERIAL=>getInstance( ).
       method getGrossWeight.
           DATA: mara type MARA.
           mara = materialDao->get( pMaterialnumber ).
           pGrossWeight = mara-brgew.

4. ZCL_DAO_MATERIAL_TEST_DOUBLE – The test double for simulating the Material Dao

  create public
  for testing .
public section.
  class-methods getTestDouble
protected section.
private section.
METHOD getTestDouble.
    DATA: lo_answer type ref to lclAnswerMaterialDaoGet.
    pMaterialDaoTestDouble ?= cl_abap_testdouble=>create( 'ZIF_DAO_MATERIAL' ).
    CREATE OBJECT lo_answer.
     cl_abap_testdouble=>configure_call( pMaterialDaoTestDouble )->ignore_all_parameters( )->set_answer( lo_answer ).
     pMaterialDaoTestDouble->get( 'DUMMY_ARTIKEL' ).

5. LclAnswerMaterialDaoGet – Local Class in ZCL_DAO_MATERIAL_TEST_DOUBLE which contains the logic for the return value

CLASS lclAnswerMaterialDaoGet DEFINITION.
public section.
    interfaces if_abap_testdouble_answer.
METHOD if_abap_testdouble_answer~answer.
      DATA: lv_src_materialnumber_data TYPE REF TO data,
            retMara type MARA.
      FIELD-SYMBOLS: <lv_src_materialnumber> TYPE MATNR,
                     <retMara> type MARA.
      lv_src_materialnumber_data = arguments->get_param_importing( 'pMaterialnumber' ).
      ASSIGN lv_src_materialnumber_data->* TO <lv_src_materialnumber>.
      if ( <lv_src_materialnumber> = 'EXISTING_ARTIKEL1' OR  <lv_src_materialnumber> = 'EXISTING_ARTIKEL2' ).
         retMara-brgew = 2.
         retMara-brgew = 0.
         result->set_param_returning( retMara ).

7. ZCL_DAO_MATERIAL_FACADE_TDOUB_UNIT – Unittest which uses the test double

"#AU Risk_Level Harmless
  private section.
   DATA: materialFacade type ref to ZCL_MATERIAL_FACADE.
       testGetGrossWeightWithTDouble FOR TESTING.
    method class_setup.
      DATA: materialDaoTestDouble type ref to ZIF_DAO_MATERIAL.
      materialDaoTestDouble = ZCL_DAO_MATERIAL_TESTDOUBLE=>getTestDouble( ).
      ZCL_DAO_MATERIAL=>setinstance( materialDaoTestDouble ).
    method setup.
      create object materialFacade.
    method testGetGrossWeightWithTDouble.
       DATA: grossWeight type mara-brgew.
       grossWeight = materialFacade->getGrossWeight( 'EXISTING_ARTIKEL1' ).
       cl_aunit_assert=>assert_equals( EXP = 2  ACT = grossWeight  MSG = '' ).
       grossWeight = materialFacade->getGrossWeight( 'EXISTING_ARTIKEL2' ).
       cl_aunit_assert=>assert_equals( EXP = 2  ACT = grossWeight  MSG = '' ).
       grossWeight = materialFacade->getGrossWeight( 'MISSING_ARTIKEL' ).
       cl_aunit_assert=>assert_equals( EXP = 0  ACT = grossWeight  MSG = '' ).

To be more accurate in the description I moved out the standard mock classes which were only for comparision reason. You can find the description for this objects in version 4.

Independent testing by mocking dependent objects.png
You must be Logged on to comment or reply to a post.
    • Hi Suhas!

      In the example code I am using the new ABAP test double framework. I packed the creation of the test double in a separate class ZCL_DAO_MATERIAL_TEST_DOUBLE (appendix 4) thus I have not to implement and configure the test double for each unit test.

      The relevant code regarding to the creation of the ABAP test double in this example is:

      1. DATA: lo_answer type ref to lclAnswerMaterialDaoGet.
      2.     pMaterialDaoTestDouble ?= cl_abap_testdouble=>create( ‘ZIF_DAO_MATERIAL’ ). 
      3.     CREATE OBJECT lo_answer.
      4.      cl_abap_testdouble=>configure_call( pMaterialDaoTestDouble )->ignore_all_parameters( )->set_answer( lo_answer ).
      5.      pMaterialDaoTestDouble->get( ‘DUMMY_ARTIKEL’ ). 

      The injection is then done in each unit test , eg. ZCL_DAO_MATERIAL_FACADE_TDOUB_UNIT (appendix 7)

      The mocking example in the end of the document is only for comparison reason, maybe I should highlight this more in the document.

      best regards, Andreas

  • Hi Andreas,

    thanks for this insight in the double test framework!

    I wonder if it is really necessary to implement such complex test doubles…

    In this case you implement a lot of lines of code just for one single value.

    I understand the idea behind it and of course this is only a show case to make me understand how this works.

    IMHO with this approach it is not possible to handle more complex data, like tables or objects.


    When doing unit testing you must design the methods in a way that unit testing is possible. For DAO you also need an interface which might not exist for an already existing class you have to use to get your data.

    so: Why do not design in a way that needed data can be inserted at the beginning of a unit test instead of calling a SELECT_DATA method?


    mt_needed_data = VALUE #( 
      ( matnr = '123' brgew = '100.00' ntgew = '90.00' mtart = 'HALB' ... )

    Especially if there is not only ONE characteristic of data you need (e.g. one material number), but different “configurations”? I think about a sales document which consists of VBAK, VBKD, VBAP, VBEP, VBPA.

    I find it really hard to get along with all test cases that are needed. If I also have to program and to maintain and check dependend data… :/


    ~ Enno

    • Hi Enno!

      First of  all the blog is some years old. The capabilities in ABAP evolved and mine too 🙂

      I remember exactly when I started to write this blog which was when I had to make a critial change in an BADI and I wanted to test not only the added logic but also if the BADI was working correct (by “injecting” the productive logic or the test double logic into the BADI implemementation.

      Well I am sure there is an easier way to do it and of course good implementations lead to unit tests without mocks.

      … and one day (on ABAP version 7.52) or higher all the mocking above is really deprecated , as then it will be done with the Open SQL test double framework – an incredible promising and powerful mocking tool in my point of view.


  • Well I am sure there is an easier way to do it and of course good implementations lead to unit tests without mocks.

    Never heard about this paradigm before… Can you explain why?

    Open SQL test double framework

    Looks as if I could insert my testdata into a kind of “test layer” where the SELECT statement takes the data from?