【问题标题】:Dependency injection to class-method in ABAPABAP中类方法的依赖注入
【发布时间】:2026-01-05 01:50:01
【问题描述】:

我有一个场景,我的类方法 (A) 调用另一个类方法 (B)。所以 A 依赖于 B。我想摆脱依赖以便能够运行单元测试。解耦和依赖注入在某种程度上是基于实例化的。但是类方法(静态方法)本质上不需要实例。 我已经制定了两个解决方案,但对我来说似乎没有一个是 100% 的:

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

我不喜欢我们需要创建一个类的实例,尽管我们是 使用类方法。这可能需要时间。它需要更多代码。

  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.

【问题讨论】:

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


    【解决方案1】:

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

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

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

    【讨论】:

    • 我还没有找到一篇关于这个主题的帖子。而且我不认为这是不可知论的。返回正确结果的代码(如这个)并不总是正确的代码(关于性能、可读性、可持续性等)。我的两种解决方案都有气味。我正在寻找 sbd 提供更好的解决方案,或者根据我的经验说“没有更好的解决方案”的专家。
    • @jcjr 搜索“依赖注入静态方法”
    • 我已经尝试过,但没有找到太多。它必须与ABAP有关。而在 ABAP 中,它通常不是命名为“静态”而是“类”方法。此外,类方法总是与单元测试一起使用;但不是作为被测代码。仅找到提及待测静态类的文章谈论部分解决方案并使用宏:blogs.sap.com/2013/08/28/dependency-injection-for-abap
    【解决方案2】:

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

    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.
    *...
    

    优点

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

    缺点

    • 社区认为肮脏的技术(仅推荐用于遗留代码)。
    • 被测代码有轻微污染。

    注意

    【讨论】:

      最近更新 更多