SAP/abap-cleaner

cx_assert does not exist

cawoodmonads opened this issue · 3 comments

There is a check that no ASSERT is used but instead cx_assert. However the class cx_assert does not exist in any SAP system we know of. How are users supposed to proceed? Create and configure a zcx_assert?

Hello cawoodmonads,

yes, the reasoning behind this is as follows:

  • When you check user input and find an inconsistency, you usually create a proper error message to inform the user what went wrong. By contrast, ASSERT is usually used in product code to express that something completely unforeseen has happened and the user can't solve it themselves (e.g. by merely changing user input), but they must inform you as the developer.
  • However, the problem of ASSERT is that it immediately dumps, even when the product code is called from a test. This means that you can only test the "happy" cases, but not the "unhappy" ones, because instead of getting a red test, test execution would dump. This is unsatisfactory, because one concern of clean code is to make code testable, i.e. to be able to safeguard the assertion with tests for both happy and unhappy cases.
  • The solution is to not use ASSERT in product code, but rather to call a "productive" assert class cx_…_assert, which has methods just like CL_ABAP_UNIT_ASSERT. So, instead of putting ASSERT it_table IS NOT INITIAL into your product code, you call cx_…_assert=>assert_not_initial( it_table ). The class then checks the condition and in case the condition is violated, raises a class based exception:
CLASS cx_xyz_assert DEFINITION PUBLIC
      INHERITING FROM cx_no_check FINAL
      CREATE PUBLIC.

  PUBLIC SECTION.
    METHODS constructor
      IMPORTING previous LIKE previous OPTIONAL.

    CLASS-METHODS assert_not_initial
      IMPORTING VALUE(act) TYPE any.

    " ...
ENDCLASS.

CLASS cx_xyz_assert IMPLEMENTATION.
  METHOD constructor.
    super->constructor( previous = previous ).
  ENDMETHOD.

  METHOD assert_not_initial.
    IF act IS INITIAL.
      RAISE EXCEPTION NEW cx_xyz_assert( ).
    ENDIF.
  ENDMETHOD.

  " ...
ENDCLASS.
  • Now you can also test the "unhappy" cases, because the test can catch a CX_XYZ_ASSERT exception and ensure it is raised.
  • Once you have such a class, the cleanup rule "Use assert class instead of ASSERT" can help you to automatically convert ASSERT statements into static CX_XYZ_ASSERT=>…( ) calls.
  • Since the desired behavior of such an CX_XYZ_ASSERT class may depend on your solution, the class name is not fixed, but can be configured in the cleanup rule. The rule is intentionally deactivated by default and the default name CX_ASSERT a non-existing class to exclude accidental use of this rule.

Kind regards,
Jörg-Michael

P.S.: Putting the "documentation" label, because it would certainly be helpful to have a better explanation within the cleanup rule (e.g. in the example code)

Hi cawoodmonads,

I meanwhile enhanced the examples of this cleanup rule with some explanation (similar to my comments above), so hopefully this is better understandable now. Thanks again for bringing it up – this is available now with version 1.18.0, which was just released!

Kind regards,
Jörg-Michael