mockA tutorial – How to create fakes

Introduction

mockA, an open source ABAP mocking framework has been released recently. The today’s blog post gives you a brief introduction of the features of mockA.
Mocking Frameworks are usually used in unit tests. Their main task is the creation of test double instances more easily than e.g. manually creating local test classes which implement an interface from which the system under test depends.
This tutorial will show you how to create so called “fakes”. Fakes usually show some kind of behavior when called. In contrast “Mocks” usually also verify that some interaction with them took please. Mocks will be subject to a future blog post.

Where to get mockA

You can download the mocking framework from Github.
Install the daily build using the latest SAPLink release.
If you like it, feel free to participate in the development of the tool.

Mocking methods with returning parameters

Interface ZIF_MOCKA_IS_IN_TIME_INFO is the interface which is to be mocked in this tutorial. The interface ships with the release of mockA. Please note that no global class implements this interface. Nevertheless, we will create local classes at runtime which allow us to create objects which can eventually be called within the same report.
Before we can create a mock object, we need to tell mockA which interface is subject to mocking:
DATA lo_mocker TYPE REF TO zif_mocka_mocker.
lo_mocker = zcl_mocka_mocker=>zif_mocka_mocker~mock( 'zif_mocka_is_in_time_info' ).

In the second step, we need to tell the mocker, which method will be mocked. Please note, that you can easily use the fluent API be directly telling the mocker, which input should lead to which method’s output:
lo_mocker->method( ‘GET_DELAY’ )->with( i_p1 = ‘LH’ i_p2 = ‘123’ i_p3 = ‘20131022’ )->returns( 30 ).

In the end, the local class implementing ZIF_MOCKA_IS_IN_TIME_INFO can be created and the mock object will be instantiated.
DATA lo_is_in_time_info TYPE REF TO zif_mocka_is_in_time_info.lo_is_in_time_info ?= lo_mocker->generate_mockup( ).

Calling the mock object with some registered method input will return the specified output.
DATA lv_delay TYPE int4.
"will return lv_delay = 30
lv_delay = lo_is_in_time_info->get_delay( iv_carrid = 'LH' iv_connid = '123' iv_fldate = '20131022' ).

Please note, that registering the same method call pattern twice leads to different method output when the method is called multiple times with parameters that fit to the registered pattern:
lo_mocker = zcl_mocka_mocker=>zif_mocka_mocker~mock( 'zif_mocka_is_in_time_info' ).
lo_mocker->method( 'GET_DELAY' )->with(
i_p1 = 'LH' i_p2 = '123' i_p3 = '20131022'
)->returns( 30 ).
lo_mocker->method( 'GET_DELAY' )->with(
i_p1 = 'LH' i_p2 = '123' i_p3 = '20131022'
)->returns( 15 ).

lo_is_in_time_info ?= lo_mocker->generate_mockup( ).
"will return lv_delay = 30
lv_delay = lo_is_in_time_info->get_delay(
iv_carrid = 'LH' iv_connid = '123' iv_fldate = '20131022' ).
"will return lv_delay = 15
lv_delay = lo_is_in_time_info->get_delay(
iv_carrid = 'LH' iv_connid = '123' iv_fldate = '20131022' ).

Mocking methods with exporting parameters

EXPORTING parameters can be returned by using the EXPORTS-Method
lo_mocker = zcl_mocka_mocker=>zif_mocka_mocker~mock(
'zif_mocka_is_in_time_info' ).
lo_mocker->method( 'GET_BOTH' )->with(
i_p1 = 'LH' i_p2 = '123' i_p3 = '20131023'
)->exports( i_p1 = 2 i_p2 = abap_true ).
lo_is_in_time_info ?= lo_mocker->generate_mockup( ).

"will return lv_delay = 2, lv_is_in_time = 'X'
lo_is_in_time_info->get_both(
EXPORTING
iv_carrid = 'LH'
iv_connid = '123'
iv_fldate = '20131023'
IMPORTING
ev_delay = lv_delay
ev_is_in_time = lv_is_in_time
).

Mocking methods with changing parameters

CHANGING parameters can serve both as input and output:
lo_mocker = zcl_mocka_mocker=>zif_mocka_mocker~mock( 'zif_mocka_is_in_time_info' ).

lo_mocker->method( 'IS_IN_TIME_BY_CHANGING_PARAM' )->with(
i_p1 = 'LH' i_p2 = '123' )->with_changing( i_p1 = lv_fldate
)->changes( '20131025' )->exports( i_p1 = abap_true ).

lo_is_in_time_info ?= lo_mocker->generate_mockup( ).

"will return lv_fldate = '20131025', lv_is_in_time = 'X'
lo_is_in_time_info->is_in_time_by_changing_param(
EXPORTING iv_carrid = 'LH' iv_connid = '123'
IMPORTING ev_is_in_time = lv_is_in_time
CHANGING cv_fldate = lv_fldate ).

Raise exceptions

Often unit tests also test unusual situations which are handled by raising and catching an exception. The mocker allows you to register a to-be-raised exception by using the methods RAISES( … ) or RAISES_BY_NAME( … )
lo_mocker = zcl_mocka_mocker=>zif_mocka_mocker~mock( 'zif_mocka_is_in_time_info' ).

lo_mocker->method( 'IS_IN_TIME' )->with(
i_p1 = 'LH' i_p2 = '123' i_p3 = '20131024' )->raises_by_name( 'zcx_mocka_in_time_exception' ).

lo_is_in_time_info ?= lo_mocker->generate_mockup( ).

TRY.
lo_is_in_time_info->is_in_time(
iv_carrid = 'LH' iv_connid = '123' iv_fldate = '20131024' ).
CATCH zcx_mocka_in_time_exception.
BREAK-POINT."program flow will halt here
CATCH cx_root.
BREAK-POINT."will not be called
ENDTRY.

Useful links

The Art of Unit Testing
Unit Tests in general

Advertisements

One thought on “mockA tutorial – How to create fakes

  1. Pingback: Uwe Kunath's Blog | mockA tutorial – How to create mocks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s