编写可测试代码的ABAP编程方法
原文链接:ABAP Programming approach to writing testable code
作者:Akash Jain 阿卡什·贾因 | August 2, 2019
无论我们的代码有多好,如果我们不能正确地测试它,修改或增强它是一项乏味的任务。这种情况会给用户和开发人员带来问题。
简介
由于需求在开发过程中经常变化,你需要不断地修改代码。有时,需求的变化可能涉及到流程的完全改变。
编写可测试的代码总是比实际测试你的代码更困难。然而,从长远来看,可测试的代码使开发人员的生活比测试代码的人更容易。
你可能会面临以下情况:
- 您需要更改自己的代码。您可能喜欢这个想法,但您不记得您最初编写的代码的细节。
- 你必须修改别人的代码。这种情况并不理想,但却很常见。
如果你不能测试代码,你怎么能确定你在实现更改后不会破坏任何东西呢?多年来,我们看到的传统方法包括以下几种:
- 在开发环境中写一些测试,并检查是否有转储的情况。
- 转移到质量测试环境,再次测试。
- 交给模块顾问,让他们在他们的终端进行测试。
- 发布给用户进行用户验收测试(UAT)。
当有人遇到代码的问题时,我们很可能会归咎于测试数据的差异。即使这是真的,真正的问题是,软件写得不好,不够健壮。没有真实的数据,你无法测试它。换句话说,程序有依赖性,你无法测试它。
测试驱动开发和 ABAP
测试驱动开发(Test-driven development,TDD)解决了这些问题,使你能够交付高质量的软件和产品。
TDD 是一个软件开发过程,它依赖于一个非常短的开发周期的重复:当需求转化为非常具体的测试用例时,软件就会被改进,只通过新的测试。(维基百科)

在 ABAP 中,所有的代码都被转换为 ABAP 单元,它只不过是一段特定的代码。测试 ABAP 单元不一定是一个由开发人员执行的纯技术过程。因为你不需要开发人员的密钥来运行 ABAP 程序的单元测试,所以任何具有显示程序或类的适当授权的人都应该能够运行测试。作为一个最佳实践,只要有可能,请尽可能让我们的业务专家和职能顾问参与测试。
行为驱动开发
行为驱动开发(Behavior-driven development,BDD)是由 TDD 产生的一种软件开发过程。BDD 将 TDD 的一般技术和原则与领域驱动设计(domain-driven design)和面向对象的分析和设计的思想相结合,为软件开发和管理团队提供共享工具和共享流程,以协作进行软件开发。(维基百科)
BDD 简化了测试方法,所以在 ABAP 单元中标注的测试方法应该有对开发人员、业务分析人员和用户有意义的描述。你可以通过设置每个测试方法使其满足 IT SHOULD(应该是这样的) 这句话来实现。
然后在这个方法里面,你通过使用以下模式创建三个辅助方法:
- GIVEN:包括程序收到的输入或初始条件。
- WHEN: 描述你要测试的活动。
- THEN:指定成功和失败的结果。
重构可测试类 Demo
下面的代码示例使用伪代码定义流程,是 zcl_instruments 类的重构测试类示例。
class lcl_test_class definition deferred.
"Allow access to private components within the class
class zcl_instruments definition local friends lcl_test_class.
class lcl_test_class definition final for testing
  duration short
  risk level harmless.
  private section.
    types: ty_guitars type standard table of zguitars with empty key.
    data: mo_class_under_test type ref to zcl_instruments,
	   guitar_instance type ref to zcl_guitar,
             guitars type ty_guitars.
	   guitar_to_add type ref to zcl_guitar.
	   guitar_to_search type ref to zcl_guitar.
	   mo_exception_raised type abap_bool.
	   found_guitars type zcl_instruments=>guitars_tab.
    methods:
      setup,
      "User Acceptance tests:
      "IT SHOULD....................
      add_guitar_to_instruments for testing,
      add_duplicate_and_get_error for testing,
      search_within_the_instruments for testing,
      "GIVEN ..................................................
      given_guitar_attribs_entered,
      given_initial_instruments,
      "WHEN ..................................................
      when_guitar_is_added,
      when_same_guitar_twice,
      when_guitar_is_searched,
      "THEN ..................................................
      then_instruments_has_guitar,
      then_exception_is_raised,
      then_guitar_is_found,
      "Other helper methods
      load_mockups returning value(re_guitars) type ty_guitars.
endclass.
您应该包括 IT SHOULD 直接从功能规范文档中出来的方法。
在此示例中,zcl_instruments 类应该能够:
- 将吉他添加到乐器中
- 限制重复行为
- 在乐器中搜索任何特定的吉他
下面的示例显示了该方法的实现 add_guitar_to_instruments() :
method add_guitar_to_instruments.
    given_guitar_attribs_entered ().
    when_guitar_is_added ().
    then_instruments_has_guitar ().
  endmethod.
若要将吉他添加到乐器,请从一些吉他属性开始,将吉他添加到乐器,然后检查是否成功添加。如果在运行此方法的测试时没有绿色,则表明过程的这一部分出了问题。
下面的 given_guitar_attribs_entered() 方法只初始化一个吉他对象。
method given_guitar_attribs_entered.
  data: guitar_spec_attributes type zcl_guitar_spec=>ty_guitar_attributes.
    guitar_spec_attributes-builder = zcl_enum_builder=>fender.
    guitar_spec_attributes-model    = 'XYZ'.
    guitar_spec_attributes-type     = zcl_enum_guit_type=>electric.
    guitar_spec_attributes-backwood = zcl_enum_wood=>maple.
    guitar_spec_attributes-topwood = zcl_enum_wood=>maple.
    data(guitar_spec) = new zcl_guitar_spec (guitar_spec_attributes).
    data(guitar_record) = value zcl_guitar=>ty_guitar_attributes (serialnumber = 'ABC0001'
                                                                   price = '1000'
                                                                   specs = guitar_spec).
    guitar_to_add = new zcl_guitar (guitar_record).
  endmethod.
BDD WHEN 描述的一部分,来自被测试的类,使您能够测试该方法。
method when_guitar_is_added.
    try.
        mo_class_under_test->add_guitar (guitar_to_add).
      catch zcx_guitar.
        "Oops
    endtry.
  endmethod.
最后,您可以使用以下方法检查对象乐器是否有吉他。此检查表示BDD部分的helper方法 Then 。
method then_instruments_has_guitar.
    data(guitar) = mo_class_under_test->guitars [ serial_number = 'ABC0001'].
    cl_abap_unit_assert=>assert_not_initial (act = guitar
                                             msg = 'Guitar is not in instruments').
  endmethod.
总结
本博客强调了编写可测试代码的重要性,并展示了如何做到这一点。通过专注于测试驱动开发,您可以调整您的编程风格以包含可测试代码。因此,您最终会得到干净、易于维护和可重用的代码。编写可测试的代码可以帮助你成为一个更好的开发人员。有时,当交付期限更紧时,很容易忽略代码的可测试性方面,这样做可能会保存时间。然而,从长远来看,您最终会花费更多的时间和资源来修复 bug。
因此,通过采用这里描述的测试驱动开发概念,您不仅可以使自己的工作更轻松,而且还可以帮助下一个开发您的代码的开发人员。
- 点赞
- 收藏
- 关注作者
 
             
           
评论(0)