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