在 ABAP 单元测试中模拟 sy-uname
Mock sy-uname in ABAP Unit test
我正在尝试用 ABAP 编写我的第一个单元测试。
我的测试方法获取登录用户的团队成员(通过系统变量sy-uname
)。
由于我希望对每个人进行 运行 测试,所以我不能只让方法 运行 断言我自己的团队成员之一。
我想模拟 sy-uname
,所以测试不依赖于执行它的人。
这可能吗?如果是,你如何模拟系统参数?
据我所知,模拟系统参数是不可能的。有两种方法可以实现这一点。
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,可能会将实例作为参数传递给多个方法。这导致复杂性增加和性能下降。如果存在需要系统变量以外的其他值的场景,这可能是合理的。
测试接缝会降低生产代码的可读性,因此可能被视为源代码污染。然而,需要考虑是否需要额外的参数不会引入更多的噪音。
我正在尝试用 ABAP 编写我的第一个单元测试。
我的测试方法获取登录用户的团队成员(通过系统变量sy-uname
)。
由于我希望对每个人进行 运行 测试,所以我不能只让方法 运行 断言我自己的团队成员之一。
我想模拟 sy-uname
,所以测试不依赖于执行它的人。
这可能吗?如果是,你如何模拟系统参数?
据我所知,模拟系统参数是不可能的。有两种方法可以实现这一点。
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,可能会将实例作为参数传递给多个方法。这导致复杂性增加和性能下降。如果存在需要系统变量以外的其他值的场景,这可能是合理的。
测试接缝会降低生产代码的可读性,因此可能被视为源代码污染。然而,需要考虑是否需要额外的参数不会引入更多的噪音。