在 ABAP 单元测试中模拟 sy-uname

Mock sy-uname in ABAP Unit test

我正在尝试用 ABAP 编写我的第一个单元测试。

我的测试方法获取登录用户的团队成员(通过系统变量sy-uname)。

由于我希望对每个人进行 运行 测试,所以我不能只让方法 运行 断言我自己的团队成员之一。

我想模拟 sy-uname,所以测试不依赖于执行它的人。

这可能吗?如果是,你如何模拟系统参数?

据我所知,模拟系统参数是不可能的。有两种方法可以实现这一点。

1.TEST-SEAM/TEST-INJECTION

TEST-SEAM sy_uname.
   DATA(lv_uname) = sy-uname.
END-TEST-SEAM.  
"other code 

你的单元测试:

TEST-INJECTION y_uname.
   lv_name = "my_mock_user".
END-TEST-INJECTION.

2.Test双

定义接口

INTERFACE if_user

  METHODS get_uname
    RETURNING 
     VALUE(rv_uname) TYYPE syst_uname.

ENDINTERFACE.

在您的生产代码中,您创建了一个 CLASS 来实现这个接口,并且 在 get_uname 到 return sy-uname 之间。

在你的代码中的某个地方,你需要提供一个 SET 方法来设置 IF_USER 的实例,如下所示,在生产代码中你调用 if_user~get_uname 的实例来获取用户名。

METHODS set_user_provider
  IMPORTING 
    !io_user_provider TYPE REF TO if_user.

在你的单元测试代码中,你创建了一个本地 CLASS 来实现这个接口并且 在 get_uname 到 return 你的模拟用户。

CLASS lcl_mock_user_provider DEFINITION FOR TESTING. 
   PUBLIC SECTION.
     INTERFACES if_user.
ENDCLASS. 

CLASS lcl_mock_user_provider IMPLEMENTATION.
   METHOD if_user~get_uname.
     "return your mock user name. 
   ENDMETHOD. 
ENDCLASS.

你的单元测试代码:

DATA(lo_mock_user_provider) = NEW lcl_mock_user_provider( ).

MyClassInstance.set_user_provider( lo_mock_user_provider ). 

我同意豪杰给出的答案一半:应该这么简单的情况下使用Test Seams (exist since ABAP 7.50)(替换sy-uname),你应该只使用他建议的供应商 class。

测试接缝被认为是生产代码的污染,因为它降低了代码的可读性(生产代码和测试代码的混合)。

注意:测试接缝的 ABAP 文档(link 以上)至少给出了以下可能的用法:

  • 授权检查 (AUTHORITY-CHECK)
  • ABAP SQL 语句(SELECT、MODIFY 等)——这成为了一个糟糕的例子,因为 ABAP SQL 可以用 ABAP 7.52 class CL_OSQL_TEST_ENVIRONMENT.

根据经验,根本不应使用测试接缝,或将其视为万不得已的解决方案。

但是如果没有其他选择,比如向 "legacy" 代码添加测试(旧的、写得很糟糕的代码,通常不是使用面向对象的设计模式编写的,被认为无法通过 ABAP 单元测试) , 那么你最终可能别无选择。

Horst Keller (one of best ABAP experts in the world and responsible of ABAP documentation at SAP)所述:

"If you cannot redesign and rewrite the whole application, as a workaround you make the code test dependent. This is regarded as bad style, but it helps."

因为问题只是关于 sy-uname 而不是关于整个程序,所以重构 sy-uname 的工作要少得多,所以没有理由不使用 class.

关于只替换一个系统变量,我会去测试接缝。

通过接口封装系统变量,需要调用者实例化class,可能会将实例作为参数传递给多个方法。这导致复杂性增加和性能下降。如果存在需要系统变量以外的其他值的场景,这可能是合理的。

测试接缝会降低生产代码的可读性,因此可能被视为源代码污染。然而,需要考虑是否需要额外的参数不会引入更多的噪音。