Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

ABAP Unit Tests for events

EnnoWulff
Active Contributor
703

Hello ABAPers!

Short question: How do I unit test events of an object?

Sample code: a global class that raises an event after some data was changed:

CLASS zcl_enno_001 DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    TYPES: BEGIN OF _dataline,
             value TYPE string,
           END OF _dataline,
           _datatable TYPE SORTED TABLE OF _dataline WITH UNIQUE KEY value.
    EVENTS something_changed.
    METHODS add_data
      IMPORTING
        i_data TYPE clike.
    METHODS get_data
      RETURNING VALUE(r_data) TYPE _datatable.
  PROTECTED SECTION.
  PRIVATE SECTION.

    DATA data TYPE _datatable.

ENDCLASS.


CLASS zcl_enno_001 IMPLEMENTATION.

  METHOD add_data.

    IF NOT line_exists( data[ value = i_data ] ).
      INSERT VALUE #( value = i_data ) INTO TABLE data.
      RAISE EVENT something_changed.
    ENDIF.
  ENDMETHOD.

  METHOD get_data.
    r_data = data.
  ENDMETHOD.

ENDCLASS.

My (so far) unit test:

CLASS ltcl_event DEFINITION FINAL FOR TESTING
  DURATION SHORT
  RISK LEVEL HARMLESS.

  PRIVATE SECTION.
    METHODS on_something_changed
                FOR EVENT something_changed OF zcl_enno_001
      IMPORTING sender.
    METHODS change_something FOR TESTING.
ENDCLASS.


CLASS ltcl_event IMPLEMENTATION.

  METHOD change_something.
    DATA(cut) = NEW zcl_enno_001( ).
    cut->add_data( 'ABCD' ).
    SET HANDLER on_something_changed FOR cut.
    cl_abap_unit_assert=>assert_equals(
      act = cut->get_data( )
      exp = VALUE zcl_enno_001=>_datatable( ( value = `ABCD` ) ) ).
  ENDMETHOD.

  METHOD on_something_changed.
    cl_abap_unit_assert=>assert_bound( sender ).
  ENDMETHOD.

ENDCLASS.

Problem: the event handler method might be called, but I cannot prove with a unit test, because I cannot mark the handler method as FOR TESTING and therefore it will not be logged:

any ideas?

Thanks
~Enno

1 ACCEPTED SOLUTION

FredericGirod
Active Contributor
481

Hi enno.wulff ,

As usual with Abap Unit, I think you should only test the responsiblity of the class. Means, check the event is raised. And to catch the event, maybe you could create a Mock

I make a little test, it seems to work.

My class to be tested :

CLASS lc_class_event
DEFINITION.
PUBLIC SECTION.
EVENTS something_changed.
METHODS set_data
IMPORTING
value TYPE string
RETURNING
VALUE(success) TYPE abap_bool.
METHODS get_data
RETURNING
VALUE(result) TYPE string.
PRIVATE SECTION.
DATA gv_value TYPE string.
ENDCLASS.


CLASS lc_class_event
IMPLEMENTATION.
METHOD set_data.
gv_value = value.
RAISE EVENT something_changed.
ENDMETHOD.
METHOD get_data.
result = gv_value.
ENDMETHOD.
ENDCLASS.

The Mock of the Event Handler :

CLASS lc_class_handler_mock
DEFINITION.
PUBLIC SECTION.
METHODS catch_event_something_change
FOR EVENT something_changed OF lc_class_event.
METHODS is_something_changed_raised
RETURNING
VALUE(result) TYPE abap_bool.
PRIVATE SECTION.
DATA gv_something_changed_raised TYPE abap_bool.
ENDCLASS.

CLASS lc_class_handler_mock
IMPLEMENTATION.
METHOD catch_event_something_change.
gv_something_changed_raised = abap_true.
ENDMETHOD.
METHOD is_something_changed_raised.
result = gv_something_changed_raised.
ENDMETHOD.
ENDCLASS.

And the test class:

CLASS lc_test_event
DEFINITION FINAL FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS..
PRIVATE SECTION.
METHODS setup.
METHODS test_event_raised FOR TESTING.
DATA o_cut TYPE REF TO lc_class_event.
DATA o_event TYPE REF TO lc_class_handler_mock.
ENDCLASS.

CLASS lc_test_event
IMPLEMENTATION.
METHOD setup.
o_cut = NEW #( ).
o_event = NEW #( ).
SET HANDLER o_event->catch_event_something_change FOR o_cut.
ENDMETHOD.
METHOD test_event_raised.
" Given I set a new value
o_cut->set_data( `Abc` ).
" Then it should raised an event
cl_abap_unit_assert=>assert_true(
act = o_event->is_something_changed_raised( ) ).
ENDMETHOD.
ENDCLASS.
2 REPLIES 2

FredericGirod
Active Contributor
482

Hi enno.wulff ,

As usual with Abap Unit, I think you should only test the responsiblity of the class. Means, check the event is raised. And to catch the event, maybe you could create a Mock

I make a little test, it seems to work.

My class to be tested :

CLASS lc_class_event
DEFINITION.
PUBLIC SECTION.
EVENTS something_changed.
METHODS set_data
IMPORTING
value TYPE string
RETURNING
VALUE(success) TYPE abap_bool.
METHODS get_data
RETURNING
VALUE(result) TYPE string.
PRIVATE SECTION.
DATA gv_value TYPE string.
ENDCLASS.


CLASS lc_class_event
IMPLEMENTATION.
METHOD set_data.
gv_value = value.
RAISE EVENT something_changed.
ENDMETHOD.
METHOD get_data.
result = gv_value.
ENDMETHOD.
ENDCLASS.

The Mock of the Event Handler :

CLASS lc_class_handler_mock
DEFINITION.
PUBLIC SECTION.
METHODS catch_event_something_change
FOR EVENT something_changed OF lc_class_event.
METHODS is_something_changed_raised
RETURNING
VALUE(result) TYPE abap_bool.
PRIVATE SECTION.
DATA gv_something_changed_raised TYPE abap_bool.
ENDCLASS.

CLASS lc_class_handler_mock
IMPLEMENTATION.
METHOD catch_event_something_change.
gv_something_changed_raised = abap_true.
ENDMETHOD.
METHOD is_something_changed_raised.
result = gv_something_changed_raised.
ENDMETHOD.
ENDCLASS.

And the test class:

CLASS lc_test_event
DEFINITION FINAL FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS..
PRIVATE SECTION.
METHODS setup.
METHODS test_event_raised FOR TESTING.
DATA o_cut TYPE REF TO lc_class_event.
DATA o_event TYPE REF TO lc_class_handler_mock.
ENDCLASS.

CLASS lc_test_event
IMPLEMENTATION.
METHOD setup.
o_cut = NEW #( ).
o_event = NEW #( ).
SET HANDLER o_event->catch_event_something_change FOR o_cut.
ENDMETHOD.
METHOD test_event_raised.
" Given I set a new value
o_cut->set_data( `Abc` ).
" Then it should raised an event
cl_abap_unit_assert=>assert_true(
act = o_event->is_something_changed_raised( ) ).
ENDMETHOD.
ENDCLASS.

0 Kudos
481

Thanks a lot frdric.girod ! It worked this way!