Names Methods: Object orientation Don’t mix stateful and stateless in the Use descriptive names Prefer instance to static methods max_wait_time_in_seconds, iso3166tab. same class METHODS a CLASS-METHODS a Language Classes: Scope Public instance methods should be part Members PRIVATE by default, Prefer object orientation over of an interface PROTECTED only if needed imperative programming INTERFACES the_interface. METHODS a I.e. classes over functions and reports Testing: Principles Prefer functional over procedural Write testable code Methods: Method body language constructs There are no tricks to writing tests, there are only Do one thing, do it well, do it only E.g. index += 1 or index = index + 1 tricks to writing testable code. (Google) Instead of ADD 1 to index Descend one level of abstraction Enable others to mock you do_something_high_level ( ). CLASS my_super_object DEFINITION. DATA(low_level_op) = |a { b }|. Comments INTERFACES you_can_mock_this. Express yourself in code, not in Keep methods small Readability rules 3-5 statements, one page, 1000 lines comments given_some_data( ). do_the_good_thing( ). Delete code instead of commenting it and_assert_that_it_worked( ). Methods: Parameter number Aim for few IMPORTING parameters, at Formatting Test classes best less than three Be consistent Call local test classes by their purpose METHODS a IMPORTING b c d e CLASS unit_tests Optimize for reading, not for writing CLASS tests_for_the_class_under_test Split methods instead of adding Constants OPTIONAL parameters Code under test METHODS a IMPORTING b Use constants instead of magic Test interfaces, not classes METHODS c IMPORTING d METHODS x numbers DATA cut TYPE REF TO some_interface IMPORTING b E.g. typekind_date instead of 'D' DATA cut TYPE REF TO some_class D
Tables Injection RETURN, EXPORT, or CHANGE exactly
Use the right table type Use test seams as temporary one parameter METHODS do_it HASHED: large, filled at once, never modified, workaround EXPORTING a read often They are not a permanent solution! CHANGING b SORTED: large, always sorted, filled over time or modified, read often Don’t misuse LOCAL FRIENDS to invade Error handling: Return codes STANDARD: small, array-like the tested code CLASS unit_tests LOCAL FRIENDS cut. Prefer exceptions to return codes METHODS check RAISING EXCEPTION Booleans cut->db_reader = stub_db_reader METHODS check RETURNING result Use XSDBOOL to set Boolean variables Test Methods Don’t let failures slip through empty = xsdbool( itab IS INITIAL ) DATA(result) = check( input ) Test methods names: reflect what’s IF result = abap_false. Conditions given and expected Try to make conditions positive METHODS accepts_emtpy_user_input Error handling: Exceptions METHODS test_1 IF has_entries = abap_true. Exceptions are for errors, not for Use given-when-then Consider decomposing complex given_some_data( ). regular cases conditions do_the_good_thing( ). Use class-based exceptions DATA(example_provided) = xsdbool(…) assert_that_it_worked( ). METHODS do_it RAISING EXCEPTION IF example_provided = abap_true AND one_example_fits = abap_true. “When” is exactly one call METHODS do_it EXCEPTIONS given_some_data( ). Ifs do_the_good_thing( ). Error handling: Throwing and_another_good_thing( ). Throw one type of exception Keep the nesting depth low assert_that_it_worked( ). METHODS a RAISING EXCEPTION b c d ELSE. IF <other>. Assertions Throw CX_STATIC_CHECK for ELSE. IF <something>. Few, focused assertions manageable situations assert_not_initial( itab ). RAISE EXCEPTION no_customizing Regular expressions assert_equals( act = itab exp = exp ). Throw CX_NO_CHECK for usually Consider assembling complex regular Use the right assert type unrecoverable situations assert_equals( act = itab exp = exp ). expressions RAISE EXCEPTION db_unavailable assert_true( itab = exp ). CONSTANTS classes … CONSTANTS interfaces … Assert content, not quantity Error handling: Catching … = |{ classes }|{ interfaces }|. assert_contains_message( key ) assert_equals( act = lines( messages ) Wrap foreign exceptions instead of Classes: Object orientation exp = 3 ). letting them invade your code CATCH foreign INTO DATA(error). Prefer objects to static classes Assert quality, not content RAISE EXCEPTION NEW my( error ). assert_all_lines_shorter_than( … ) RAISE EXCEPTION error. Prefer composition over inheritance DATA delegate TYPE REF TO
Clean ABAP The Golden Rules v1.1.1 PUBLIC https://github.com/SAP/styleguides/blob/master