对ABAP中的类方法的依赖注入

时间:2018-07-11 13:51:45

标签: unit-testing dependency-injection static-methods abap interpreted-language

在我的类方法(A)调用另一个类方法(B)的情况下。因此,A依赖于B。我希望摆脱依赖关系,以便能够运行单元测试。解耦和依赖注入在某种程度上基于实例。但是类方法(静态方法)本质上不需要实例。 我已经使两种解决方案都能正常工作,但对我来说,它们似乎都不是100%:

  1. 我们创建类B的实例(生产代码)或测试double的实例(用于单元测试)。我们将其作为参数输入到被测类方法中。内部类方法在注入的实例上调用,而不是在类上调用。
  

我不希望我们需要创建类的实例,尽管我们   使用类方法。可能需要一些时间。它需要更多代码。

  1. 我们将实际的类名作为字符串参数注入,并使用动态CALL METHOD
  

由于我不喜欢解释性语言,因此我认为这很混乱   会带来严重的运行时问题。因为我们这样做是为了实现单位   测试并因此消除可能的错误;使用动态调用似乎   适得其反。使用参数也很麻烦。

还有另一种解决方法吗?我错过了一些重要的观点吗?

以下是这两种解决方案的关键部分。理解问题不是必需的,但可能会有所帮助。

1)

INTERFACE lif_readfile.
  CLASS-METHODS gui_upload
    IMPORTING file_path TYPE string
    CHANGING data_tab  TYPE truxs_t_text_data.
ENDINTERFACE.

CLASS lcl_file_operations DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS:
      get_file_length
        IMPORTING
          !file_path         TYPE string
        CHANGING
          !filereader        TYPE REF TO lif_readfile OPTIONAL
        RETURNING
          VALUE(text_length) TYPE i.
ENDCLASS.

CLASS lcl_file_operations IMPLEMENTATION.
  METHOD get_file_length.

*create instance of default productive class
    IF filereader IS NOT BOUND.
      filereader = NEW lcl_readfile( ).
    ENDIF.

*use instance to call class method
    filereader->gui_upload(
      EXPORTING file_path = file_path
        CHANGING data_tab = lt_data
    ).

*code under test here..

  ENDMETHOD.
ENDCLASS.

2)

CLASS lcl_file_operations DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS:
      get_file_length
        IMPORTING
          !file_path         TYPE string
          !classname         TYPE string DEFAULT 'LCL_READFILE'
        RETURNING
          VALUE(text_length) TYPE i.
ENDCLASS.

CLASS lcl_file_operations IMPLEMENTATION.
  METHOD get_file_length.

*parameter definition
    ptab = VALUE #( ( name  = 'FILE_PATH'
                      kind  = cl_abap_objectdescr=>exporting
                      value = REF #( file_path ) )
                    ( name  = 'DATA_TAB'
                      kind  = cl_abap_objectdescr=>changing
                      value = REF #( lt_data ) ) ).

    DATA(meth)     = 'LIF_READFILE~GUI_UPLOAD'.

*dynamic call
    CALL METHOD (classname)=>(meth) PARAMETER-TABLE ptab.

*code under test here..

  ENDMETHOD.
ENDCLASS.

2 个答案:

答案 0 :(得分:0)

我认为您的问题与语言无关。您是否检查了论坛中提供的多个答案,并且对提出的不同方法有何看法?

您可以使用 instance 方法将静态调用包装在新接口和类中,该方法映射到静态指定的正确类的静态方法。

ABAP特有的关于使用“类名”作为变量的解决方案,正如您所显示的,我个人不喜欢它,但是我认为这只是个人喜好,并不重要。 PS:术语“解释语言”是一种编程语言,与之相反(为简单起见)是“编译语言”;您所说的更多是关于dynamic link

答案 1 :(得分:0)

到目前为止,我发现了两种对我来说似乎更好的解决方案。但是,如果您知道更好的解决方案,我仍然期待尝试。

Factory + injector(依赖查找)

改进的解决方案1 ​​–实例处理已移至工厂。没有提供工厂代码和喷油器代码,这是标准解决方案。

CLASS lcl_file_operations DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS:
      get_file_length
        IMPORTING
          !file_path         TYPE string
        RETURNING
          VALUE(text_length) TYPE i.
ENDCLASS.


CLASS lcl_file_operations IMPLEMENTATION.
  METHOD get_file_length.

    myfactory=>get_filereader( )->gui_upload(
      EXPORTING file_path = file_path
        CHANGING data_tab = lt_data
    ).

*code under test here..

  ENDMETHOD.
ENDCLASS.

优点

  • 正在测试的更简洁的代码。实例是在其他地方创建和测试的。

缺点

  • 它仍然会创建实例。
  • 总共有更多代码。

使用TEST-SEAM和TEST-INJECTION

CLASS zcl_file_operations IMPLEMENTATION.
  METHOD get_file_length.

   TEST-SEAM seam_gui_upload.
     zcl_filereader=>gui_upload(
        EXPORTING file_path = file_path
        CHANGING data_tab = lt_data
     ).
   END-TEST-SEAM.

*code under test here..

  ENDMETHOD.
ENDCLASS.

用于测试方法

*...
TEST-INJECTION seam_gui_upload.
 ztc_testdouble=>gui_upload(
    EXPORTING file_path = file_path
    CHANGING data_tab = lt_data
 ).
END-TEST-INJECTION.
*...

优点

  • 这似乎是迄今为止最好的解决方案。
  • 使用类方法;没有创建实例。
  • 最短的代码。

缺点

  • 社区认为脏技术(仅推荐用于旧代码)。
  • 受测试的代码轻微污染。

注意