天天看点

四种ABAP单元测试隔离(test isolation)技术

Hi friends,

As far as I know test isolation is widely used in SAP internal to build unit test code, at least in my team. Test isolation in unit test means that in your production code you make use of some API(class method/Function module) which are developed by other team, and you would not like to really consume them during your unit test, since you would not accept that most red lights in your unit test report are caused by the bugs in those external API,right? Instead, you expect that the call of those external API during your unit test execution will be replaced by some dummy code written by yourself.

I will show you four different ways to achieve that.

The example comes from one productive class in my project. For simplicity reasons I don’t list unrelevant code here. The class is ZCL_DESTRUCTION_IMG_TOOL_S1.

四种ABAP单元测试隔离(test isolation)技术

 method RUN.

   DATA: lv_social_post_id TYPE string.

   fill_worklist( ).

   LOOP AT mt_worklist INTO lv_social_post_id.

      IF dependent_object_existed( lv_social_post_id ) = abap_false.

         delete( lv_social_post_id ).

      ENDIF.

   ENDLOOP.

 endmethod.

The worklist is just hard-coded:

method FILL_WORKLIST.

    CLEAR: mt_worklist.

    APPEND '20130001' TO mt_worklist.

    APPEND '20130002' TO mt_worklist.

    APPEND '20130003' TO mt_worklist.

The reason why test isolation is used in our unit test is because in method dependent_object_existed, we call an API provided by another team, and we don’t want that API to be really executed during our unit test execution. For demonstration reason, I use the following code to simulate the production code.

It means during the unit test on this class, the following code is NOT expected to be executed at all.

 method DEPENDENT_OBJECT_EXISTED.

    WRITE: / 'Productive code to check dependent object existence for ID: ' , iv_social_post_id.

Approach1: test subclass instead

(1) Change the visibility of method DEPENDENT_OBJECT_EXISTED from private to protected. The idea is in this approach, we create a sub class ( a local test class) which inherits from ZCL_DESTRUCTION_IMG_TOOL_S1. Since the DEPENDENT_OBJECT_EXISTED is now protected, we have the chance to redefine it in the local test class.

四种ABAP单元测试隔离(test isolation)技术
四种ABAP单元测试隔离(test isolation)技术
四种ABAP单元测试隔离(test isolation)技术

when execution comes into run method, since the subclass only redefines the very method dependent_object_existed, so the execution of the left methods are still using the code of ZCL_DESTRUCTION_IMG_TOOL_S1. That means all methods of ZCL_DESTRUCTION_IMG_TOOL_S1 except dependent_object_existed will be covered by unit test.

四种ABAP单元测试隔离(test isolation)技术
四种ABAP单元测试隔离(test isolation)技术

Approach2 – interface extraction + optional argument

The idea is to extract the logic written in method dependent_object_existed and put its implementation into method dependent_object_existed of a new interface ZIF_SOC_DEPENDENCY_DETECTOR instead. Via such abstraction, the loose coupling of dependency detection call and its implementation is achieved.

Necessary change on production class ZCL_DESTRUCTION_IMG_TOOL_S2 source code:

(1) Private method dependent_object_existed can be removed now.

四种ABAP单元测试隔离(test isolation)技术
四种ABAP单元测试隔离(test isolation)技术

Approach3 – Dynamic detector initialization

Interface extraction is also necessary for this solution.

Necessary change on production class ZCL_DESTRUCTION_IMG_TOOL_S3’s source code:

(1) Create a local class to implement the productive logic of dependency detection just the same as approach2.

(2) Add a new static member attribute for technical name of dependency class name. Default value is local class name created in step1:

四种ABAP单元测试隔离(test isolation)技术
四种ABAP单元测试隔离(test isolation)技术
四种ABAP单元测试隔离(test isolation)技术

No new attribute or method interface change is required in this solution. This solution should be used for test isolation whenever possible.

继续阅读