‎2020 Apr 22 8:11 AM
Hello,
I was trying adding my TDD in a very simple se38 program and stuck into an issue which I tried googling in forum but didn't find solution towards. So if some one has already encountered this problem, would be a great help if you please share your experience how did you resolve this piece.
Problem statement: In my legacy Program (not OOPs based) has a message statement inside a subroutine which is causing a failure to ABAP Unit test run.
Tried several approaches, seems not fruitful so far. As every time it is throwing an exception with CX_AUNIT_UNCAUGHT_MESSAGE.

May be missing something very basic!

Here the message statement is causing the issue as may be it is trying to connect with GUI, not sure.
I am handling this piece of code as below under Test Class/method:

But it is still failing and my expectation is, it should pass the test. As This message I need to be raised as per given test data and I don't want to pass the message as an exporting parameter from the process_data routine. I would like to leave the form untouched as much as possible.
Any pointers to this particular problem would be really helpful,.
Thank you. Som
‎2020 Apr 22 1:54 PM
Hello,
Plain MESSAGE statements inside code under test are "forbidden" at unit testing.
Unit Test Runtime virtually runs in a session without dialog available; MESSAGE without RAISING or INTO additions, as is on your code snippet, depends on dialog (or being run in background), so it won't work here.
Results screen gives a (faint) tip on this case in analysis tab with a imprecise text: 'MESSAGE ... raised but not handled!' (I do know that this solely won't help at all). ABAP Unit tought that your MESSAGE statement already had a RAISING addition, and no one caught it to handle before reached main code of unit test runtime environment.
You need to change your code to propagate this message instead of directly showing inside this form:
And then adjust your code where this form is called to handle exception/form protocol to display it.
Best regards
‎2020 Apr 22 8:27 AM
could you post the local test class definition & the test method definition ?
it is strange to have this kind of message in a test method
‎2020 Apr 22 1:28 PM
Shouldn't the MESSAGE statement in PROCESS_DATA have also the RAISING EXCEPTION addition if you expect an exception later?
‎2020 Apr 23 5:32 PM
Right observation thanks for pointing it out Peter. Actually I tried that but within form this is not getting accepted as Message with raising is non-class based whereas form raising ( as class based ). But this works fine within class / method. Thank You for your comment and help!
‎2020 Apr 22 1:30 PM
BTW you could also use this assertion, that way you don't need a helper variable:
cl_abap_unit_assert=>assert_bound( act =exc ).
‎2020 Apr 23 5:32 PM
Thank you, yes agree a better way to handle this case if exception gets caught into... - Regards, Som
‎2020 Apr 22 1:54 PM
Hello,
Plain MESSAGE statements inside code under test are "forbidden" at unit testing.
Unit Test Runtime virtually runs in a session without dialog available; MESSAGE without RAISING or INTO additions, as is on your code snippet, depends on dialog (or being run in background), so it won't work here.
Results screen gives a (faint) tip on this case in analysis tab with a imprecise text: 'MESSAGE ... raised but not handled!' (I do know that this solely won't help at all). ABAP Unit tought that your MESSAGE statement already had a RAISING addition, and no one caught it to handle before reached main code of unit test runtime environment.
You need to change your code to propagate this message instead of directly showing inside this form:
And then adjust your code where this form is called to handle exception/form protocol to display it.
Best regards
‎2020 Apr 23 5:32 PM
‎2020 Apr 22 3:26 PM
Hello frdric.girod,
Thanks for your comment. Here you go:
could you post the local test class definition & the test method definition ?

Thank You, Som
‎2020 Apr 22 5:11 PM
Please post the code as text instead of image, so that one can easily answer by testing your code.
‎2020 Apr 23 6:29 AM
I have rebuild a full example with something like your code
You should not use MESSAGE statement in OOo code. You have to replace it with an exception class. I have wrote a code with exception class also. You could use this exception class to keep the message number/information ..
I have also wrote the proposal of peter.inotai (because it is better to do like that)
REPORT ztest_fg029.
CLASS lx_my_error DEFINITION INHERITING FROM cx_static_check .
PUBLIC SECTION.
INTERFACES if_t100_dyn_msg .
INTERFACES if_t100_message .
CONSTANTS:
BEGIN OF failed_for_my_method,
msgid TYPE symsgid VALUE '00',
msgno TYPE symsgno VALUE '001',
attr1 TYPE scx_attrname VALUE 'GV_ERROR_INFO',
attr2 TYPE scx_attrname VALUE '',
attr3 TYPE scx_attrname VALUE '',
attr4 TYPE scx_attrname VALUE '',
END OF failed_for_my_method.
DATA gv_error_info TYPE string.
METHODS constructor
IMPORTING
!textid LIKE if_t100_message=>t100key OPTIONAL
!previous LIKE previous OPTIONAL
iv_error_info TYPE string OPTIONAL.
ENDCLASS.
CLASS lx_my_error IMPLEMENTATION.
METHOD constructor ##ADT_SUPPRESS_GENERATION.
CALL METHOD super->constructor
EXPORTING
previous = previous.
gv_error_info = iv_error_info.
CLEAR me->textid.
IF textid IS INITIAL.
if_t100_message~t100key = if_t100_message=>default_textid.
ELSE.
if_t100_message~t100key = textid.
ENDIF.
ENDMETHOD.
ENDCLASS.
CLASS lc_productive DEFINITION.
PUBLIC SECTION.
METHODS my_method RAISING lx_my_error.
METHODS my_second_method RAISING lx_my_error.
ENDCLASS.
CLASS lc_productive IMPLEMENTATION.
METHOD my_method.
MESSAGE e001(00) WITH `My_Method failed hardly`.
ENDMETHOD.
METHOD my_second_method.
RAISE EXCEPTION TYPE lx_my_error
EXPORTING
textid = lx_my_error=>failed_for_my_method
iv_error_info = `My_Method failed hardly`.
ENDMETHOD.
ENDCLASS.
CLASS ltc_productive DEFINITION
FOR TESTING
RISK LEVEL HARMLESS
DURATION SHORT
FINAL.
PRIVATE SECTION.
methods setup.
methods test_method_1 for testing raising lx_my_error.
methods test_method_2 for testing raising lx_my_error.
methods test_method_2_peter_com for testing raising lx_my_error.
DATA o_cut TYPE REF TO lc_productive.
ENDCLASS.
CLASS ltc_productive IMPLEMENTATION.
method setup.
o_cut = new #( ).
endmethod.
method test_method_1.
try.
o_cut->my_method( ).
catch lx_my_error into data(lo_exception).
data(lv_flag) = abap_true.
endtry.
cl_abap_unit_assert=>assert_equals(
act = lv_flag
exp = abap_true ).
endmethod.
method test_method_2.
try.
o_cut->my_second_method( ).
catch lx_my_error into data(lo_exception).
data(lv_flag) = abap_true.
endtry.
cl_abap_unit_assert=>assert_equals(
act = lv_flag
exp = abap_true ).
endmethod.
method test_method_2_peter_com.
try.
o_cut->my_second_method( ).
catch lx_my_error into data(lo_exception).
endtry.
cl_abap_unit_assert=>assert_bound( lo_exception ).
endmethod.
endclass.
‎2020 Apr 23 5:32 PM
Many Thanks and I appreciate your response with some good example, useful. But my problem is with PERFORM/ FORM.
As form also can raise an exception, but that is class based and message can raise an exception which is non-class based.
So I can't propagate this exception back to the caller with a message followed by raising statement but with raise exception type..... ( class based) way.
I was trying to make this work as there are many legacy code which has this kind of scenarios and whether to have any option available ( as I am not aware of but someone already has resolved with some technique) else code realignment is needed.
Class based scenarios are bit easy I found as have many options ( one already you have shared) also inhering and redefining and handle under try~catch inside. But when this is FORM and which is not under a global FM / Class bit different to handle I felt.
‎2021 Sep 08 7:57 AM
Hey Som,
I see the question is here from some time now and you have already voted for one of the answer.
But I was just wondering, what is we propagate the message class, id and number to the caller of the subroutine. And the caller checks if message details are filled and then display the message.
I still believe using local exception would be the way to go. However as you have mentioned, this is a legacy code and one might not want to make more changes (as this could involve testing which can be expensive).
What are your thoughts on this?
Regards,
Raviraj