Skip to content

Unit Test Assert Check #347

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Apr 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Whenever you upgrade code pal for ABAP, it is highly recommended to execute the

2021-04-** v.1.14.0
------------------
+ Unit Test Without/With Invalid Assert (#288)
+ Prefer NEW to CREATE OBJECT (#283)
* Standard functions in Prefer IS NOT to NOT IS (#338)
* In the profile feature, you can add all the missing checks (#346)
Expand Down
1 change: 1 addition & 0 deletions docs/check_documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@
- [Self-Reference](checks/self-reference.md)
- [TEST-SEAM Statement Usage](checks/test-seam-usage.md)
- [Unit-Test Coverages (Statement, Branch and Procedure)](checks/unit-test-coverages.md)
- [Unit-Test Assert Validator](checks/unit_test_assert.md)
59 changes: 59 additions & 0 deletions docs/checks/unit_test_assert.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
[code pal for ABAP](../../README.md) > [Documentation](../check_documentation.md) > [Unit-Test Assert Validator](unit_test_assert.md)

## Unit-Test Assert Validator

### What is the Intent of the Check?

This check verifies invalid assertions in unit tests.
It supports the `CL_ABAP_UNIT_ASSERT=>ASSERT*` and `CL_AUNIT_ASSERT=>ASSERT*`.

### How does the check work?

It checks for actual (`act`) or expected (`exp`) invalid value(s), for instance:
- When both are using the same variable for the Assertion (which will always return TRUE);
- When both are hardcoded.

### How to solve the issue?

Fix the actual (`act`) or expected (`exp`) value(s) in the unit test assertion in order to achieve a meaningful and real Assertion.

### What to do in case of exception?

In exceptional cases (if any), you can suppress this finding by using the pseudo comment `"#EC UT_ASSERT` which has to be placed after the assertion statement:

```abap
cl_abap_unit_assert=>assert_equals( act = sum
exp = sum ). "#EC UT_ASSERT
```

### Example

Before the check:

```abap
METHOD sum.
" given
DATA(first) = 10.
DATA(second) = 10.
" when
DATA(sum) = first + second.
" then
cl_abap_unit_assert=>assert_equals( act = sum
exp = sum ).
ENDMETHOD.
```

After the check:

```abap
METHOD sum.
" given
DATA(first) = 10.
DATA(second) = 10.
" when
DATA(sum) = first + second.
" then
cl_abap_unit_assert=>assert_equals( act = sum
exp = 20 ).
ENDMETHOD.
```
94 changes: 94 additions & 0 deletions src/checks/y_check_unit_test_assert.clas.abap
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
CLASS y_check_unit_test_assert DEFINITION PUBLIC INHERITING FROM y_check_base CREATE PUBLIC .
PUBLIC SECTION.
METHODS constructor.

PROTECTED SECTION.
METHODS inspect_tokens REDEFINITION.

PRIVATE SECTION.
METHODS get_act_and_exp IMPORTING statement TYPE sstmnt
EXPORTING act TYPE stokesx
exp TYPE stokesx.

METHODS is_variable IMPORTING token TYPE stokesx
RETURNING VALUE(result) TYPE abap_bool.

ENDCLASS.


CLASS y_check_unit_test_assert IMPLEMENTATION.


METHOD constructor.
super->constructor( ).

settings-pseudo_comment = '"#EC UT_ASSERT' ##NO_TEXT.
settings-disable_threshold_selection = abap_true.
settings-apply_on_productive_code = abap_false.
settings-apply_on_test_code = abap_true.
settings-threshold = 0.
settings-documentation = |{ c_docs_path-checks }unit_test_assert.md|.

relevant_statement_types = VALUE #( ( scan_struc_stmnt_type-method ) ).
relevant_structure_types = VALUE #( ).

set_check_message( 'Invalid Unit Test Assertion!' ).
ENDMETHOD.


METHOD inspect_tokens.
CHECK get_token_abs( statement-from ) CP 'CL_ABAP_UNIT_ASSERT=>ASSERT*'
OR get_token_abs( statement-from ) CP 'CL_AUNIT_ASSERT=>ASSERT*'.

get_act_and_exp( EXPORTING statement = statement
IMPORTING act = DATA(act)
exp = DATA(exp) ).

IF act IS INITIAL
OR exp IS INITIAL.
RETURN.
ENDIF.

IF act-str <> exp-str.
IF is_variable( act ) = abap_true
OR is_variable( exp ) = abap_true.
RETURN.
ENDIF.
ENDIF.

DATA(check_configuration) = detect_check_configuration( statement ).

IF check_configuration IS INITIAL.
RETURN.
ENDIF.

raise_error( statement_level = statement-level
statement_index = index
statement_from = statement-from
error_priority = check_configuration-prio ).
ENDMETHOD.


METHOD get_act_and_exp.
LOOP AT ref_scan_manager->tokens ASSIGNING FIELD-SYMBOL(<token>)
FROM statement-from TO statement-to.
DATA(tabix) = sy-tabix.
CASE <token>-str.
WHEN 'ACT'.
act = ref_scan_manager->tokens[ tabix + 2 ].
WHEN 'EXP'.
exp = ref_scan_manager->tokens[ tabix + 2 ].
WHEN OTHERS.
CONTINUE.
ENDCASE.
ENDLOOP.
ENDMETHOD.


METHOD is_variable.
result = COND #( WHEN token-type = scan_token_type-literal THEN abap_false
WHEN token-type = scan_token_type-identifier THEN xsdbool( token-str CN '0123456789' ) ).
ENDMETHOD.


ENDCLASS.
Loading