我正在尝试用ABAP编写我的第一个单元测试。
我测试的方法获取登录用户的团队成员(通过系统变量sy-uname
(。
由于我希望测试为每个人运行,因此我不能只是让该方法运行并断言我自己的团队成员之一。
我想模拟sy-uname
,所以测试不依赖于谁在执行它。
这可能吗?如果是,您如何模拟系统参数?
我半同意 Haojie 给出的答案:对于如此简单的情况(替换sy-uname
(,不应该使用 Test Seams(自 ABAP 7.50 以来存在(,您应该只使用他建议的提供程序类。
测试接缝被认为是对生产代码的污染,因为它降低了代码的可读性(生产代码和测试代码的混合(。
注意:测试接缝的ABAP文档(上面的链接(至少给出了以下可能的用法:
- 授权检查(权限检查(
- ABAP SQL语句(SELECT,MODIFY等( - 它成为一个不好的例子,因为ABAP SQL可以用ABAP 7.52类
CL_OSQL_TEST_ENVIRONMENT
来模拟。
根据经验,根本不应使用测试接缝,也不应将其视为最后的解决方案。
但是,如果没有其他选择,比如将测试添加到"遗留"代码中(编写得很糟糕的旧代码,通常不使用面向对象的设计模式编写,被认为无法通过ABAP Unit进行测试(,那么您最终可能别无选择。
正如Horst Keller(世界上最好的ABAP专家之一,负责SAP的ABAP文档(所说:
"如果你不能重新设计和重写整个应用程序,作为一种解决方法,你使代码测试依赖于。这被认为是不好的风格,但它有帮助。
由于问题只是关于sy-uname
而不是关于整个程序,所以重构sy-uname
的努力要少得多,所以没有理由不使用类。
据我所知,不可能模拟系统参数。 有两种方法可以实现此目的。
1.试缝/试注塑
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.测试双
定义接口
INTERFACE if_user
METHODS get_uname
RETURNING
VALUE(rv_uname) TYYPE syst_uname.
ENDINTERFACE.
在生产代码中,创建一个 CLASS 来实现此接口,并且 在返回sy-uname
get_uname
.
在代码中的某个地方,您需要提供一个 SET 方法,以便能够设置如下所示的IF_USER实例,在生产代码中,您调用if_user~get_uname
的实例以获取用户名。
METHODS set_user_provider
IMPORTING
!io_user_provider TYPE REF TO if_user.
在单元测试代码中,创建一个本地 CLASS 来实现此接口和 在get_uname返回您的模拟用户。
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 ).
关于只替换一个系统变量,我会去测试接缝。
通过接口封装系统变量,需要调用方实例化类,可能将实例作为参数传递给多个方法。这会导致复杂性增加和性能下降。如果存在需要系统变量以外的其他值的方案,则这可能是合理的。
测试接缝会降低生产代码的可读性,因此可能被视为对源代码的污染。然而,人们需要考虑是否需要额外的参数,甚至不会引入更多的噪声。