简体   繁体   English

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

[英]Mock sy-uname in ABAP Unit test

I am trying to write my first unit tests in ABAP.我正在尝试在 ABAP 中编写我的第一个单元测试。

My method under test fetches team members of the logged-on user (via system variable sy-uname ).我的测试方法获取登录用户的团队成员(通过系统变量sy-uname )。

Since I want the test to run for everyone I can't just let the method run and assert one of my own team members.因为我希望测试对每个人都运行,所以我不能让方法运行并断言我自己的团队成员之一。

I want to mock sy-uname , so the test is not dependent on who is executing it.我想模拟sy-uname ,所以测试不依赖于执行它的人。

Is this possible?这可能吗? If yes how do you mock system parameters?如果是,你如何模拟系统参数?

I half agree with the answers given by Haojie: one should not use Test Seams (exist since ABAP 7.50) for a so simple case (replacing sy-uname ), you should only use a provider class as he proposed.我一半同意由豪杰给出的答案:一个人应该使用测试接缝(因为ABAP 7.50存在)一个这么简单的情况下(更换sy-uname ),你应该只因为他提出的使用提供程序类。

Test seams are considered like a pollution of the productive code, because it reduces the readability of the code (mix of productive and test code).测试接缝被认为是对生产代码的污染,因为它降低了代码的可读性(生产代码和测试代码的混合)。

NB: the ABAP documentation of test seams (link above) gives at least the following possible usages:注意:测试接缝的 ABAP 文档(上面的链接)至少给出了以下可能的用法:

  • Authorization checks (AUTHORITY-CHECK)授权检查(AUTHORITY-CHECK)
  • ABAP SQL statements (SELECT, MODIFY, etc.) - It became a bad example since ABAP SQL can be mocked with the ABAP 7.52 class CL_OSQL_TEST_ENVIRONMENT . ABAP SQL 语句(SELECT、MODIFY 等)——这是一个糟糕的例子,因为可以使用 ABAP 7.52 类CL_OSQL_TEST_ENVIRONMENT ABAP SQL。

As a rule-of-thumb, test seams should not be used at all, or considered as a solution of very last resort.根据经验,根本不应使用测试接缝,也不应将其视为最后的解决方案。

BUT if there's no other choice, like adding tests to a "legacy" code (old-badly-written code, usually not written using object-oriented design patterns, that is considered not testable via ABAP Unit), then you may have eventually no other choice.但是,如果没有其他选择,比如向“遗留”代码添加测试(写得不好的旧代码,通常不是使用面向对象的设计模式编写的,被认为无法通过 ABAP 单元进行测试),那么您最终可能没有其他选择。

As stated by Horst Keller (one of best ABAP experts in the world and responsible of ABAP documentation at SAP) :正如Horst Keller(世界上最好的 ABAP 专家之一,负责 SAP 的 ABAP 文档)所述

"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." “如果你不能重新设计和重写整个应用程序,作为一种解决方法,你可以让代码测试依赖。这被认为是糟糕的风格,但它有帮助。”

As the question is only about sy-uname and it's not about the whole program, so the effort to refactor sy-uname is much lesser, so there's no excuse to not using a class.由于问题仅关于sy-uname而不是关于整个程序,因此重构sy-uname的工作要少得多,所以没有理由不使用类。

It is not possible to mock system parameters as far as i know.据我所知,不可能模拟系统参数。 there are two ways to achieve this.有两种方法可以实现这一点。

1. TEST-SEAM/TEST-INJECTION 1. 试缝/试射

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

Your unit test:你的单元测试:

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

2.Test Double 2.测试替身

Define a interface定义一个接口

INTERFACE if_user

  METHODS get_uname
    RETURNING 
     VALUE(rv_uname) TYYPE syst_uname.

ENDINTERFACE.

In your production code, you create a CLASS to implement this interface and in the get_uname to return sy-uname .在您的生产代码中,您创建一个 CLASS 来实现此接口,并在get_uname中返回sy-uname

somewhere in your code, you need to provide a SET method to be able to set the instance of IF_USER like below, and in the production code you call the instance of if_user~get_uname to get the user name.在您的代码中的某处,您需要提供一个 SET 方法来设置 IF_USER 的实例,如下所示,并在生产代码中调用if_user~get_uname的实例来获取用户名。

METHODS set_user_provider
  IMPORTING 
    !io_user_provider TYPE REF TO if_user.

In your unit test code, you create a local CLASS to implement this interface and in the get_uname to return your mock 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.

your unit test code:您的单元测试代码:

DATA(lo_mock_user_provider) = NEW lcl_mock_user_provider( ).

MyClassInstance.set_user_provider( lo_mock_user_provider ). 

With regards to replace just one system variable I would go for test seams.关于只替换一个系统变量,我会去测试接缝。

Encapsulating system variables by an interface, requires caller to instantiate the class, maybe to pass the instance over multiple methods as parameter.通过接口封装系统变量,需要调用者实例化类,可能将实例作为参数传递给多个方法。 This causes an increased complexity and decline of performance.这会导致复杂性增加和性能下降。 This might be justified if there are scenarios with the need of other values than the system variable.如果存在需要系统变量以外的其他值的场景,这可能是合理的。

Test seams decrease readability of your productive code and thus might be regarded as pollution of the source code.测试接缝会降低生产代码的可读性,因此可能会被视为对源代码的污染。 One however needs to consider if a need of additional parameters introduces not even more noise.然而,需要考虑是否需要额外的参数不会引入更多的噪音。

There is a nice class from SAP that contains system parameters that can be mocked. SAP提供了一个很好的类,它包含可以模拟的系统参数。 For sy-uname , use cl_abap_syst=>get_user_name( ) instead. 对于sy-uname ,请改用cl_abap_syst=>get_user_name( )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM