ABAP Test Double Framework versus mockA

I recently had the chance to have a look into SAP’s ABAP Test Double Framework. Previously, the main tool for mock object creation was mockA, which did a great job in my previous projects.

Code readability

The Test Double Framework’s fake object creation is quite straight forward. Creating such an instance is handy and even allows you to use the native method call to specify the importing-parameters. Please see the blog post from SAP:

"create test double object
lo_currency_converter_double ?= cl_abap_testdouble=>create( 'if_td_currency_converter' ).

“configuration for stubbing method ‘convert’:
“step 1: set the desired returning value for the method call
cl_abap_testdouble=>configure_call( lo_currency_converter_double )->returning( 80 ).
“step 2: specifying which method should get stubbed
lo_currency_converter_double->convert(
EXPORTING
amount = 100
source_currency = ‘USD’
target_currency = ‘EUR’
).

The same test double configuration in mockA:

"create test double object
lo_currency_converter_double ?= zcl_mocka_mocker=>zif_mocka_mocker~mock( 'if_td_currency_converter' )->method( ‘convert’ )->with( i_p1 = 100 i_p2 = ‘USD’ i_p3 = ‘EUR’ )->returns( 80 )->generate_mockup( ).

As you can see, mockA doesn’t allow to verify whether you correctly supplied the method’s importing-parameters and method name at design time. This restriction applies for the Test Double Framework only for exporting and changing-parameters.
The only two disadvantages that I’ve recognized are

  • checked exceptions need to be catched in a dummy TRY…CATCH…RETURN…ENDTRY-statement to avoid ATC messages
  • the exporting- and returning parameters specification comes before the actual method call specification and configuration of the importing parameter. You need to get used to it, but it’s fine

Let the framework ignore importing parameters

The Test Double Framework allows you to separately ignore importing parameters by attaching “->ignore_parameter(…)” to your “configure_call(…)” method call. This feature is not yet existent in mockA. However, if you avoid the “->with(…)” method call in mockA completely, it will return the specified output in any case . This is equivalent to “->ignore_all_parameters(…)”.

Verify interactions

Quite handy in the Test Double Framework. Just call

cl_abap_testdouble=>verify_expectations( lo_currency_converter_double ).

..and let the framework assert that your specified methods have been called as intended.

mockA requires you to store the mock creation object of type ZIF_MOCKA_MOCKER.
It allows you to verify method calls like this:

cl_abap_unit_assert=>assert_true( mo_mocker->method( 'convert' )->has_been_called_with( i_p1 = 100 i_p2 = 'USD' i_p3 = 'EUR' ) ).

Custom matchers

The Test Double Framework allows you to pass custom matchers which will implement interaction verifications on the fake method input parameters. The interface is called if_abap_testdouble_matcher and it is very easy to implement. mockA does not offer such a concept.

System requirements

mockA requires NW 7.01. The Test Double Framework requires NW 7.40.

Object support

mockA supports classes and interfaces, while the Test Double Framework supports interfaces, but no classes at the moment.

Conclusion

The Test Double Framework is a really nice mocking framework. It works very well and offers functionality, which mockA doesn’t offer. However, some drawbacks still exist, e.g. when you want to mock classes or work with NW releases lower than 7.40

mockA – Carry out checks against parameters passed to the mock object’s methods

What has been missing so far

In one of my last blog posts, I showed you how mock objects can be easily created. I also showed you how mock object’s method calls can be counted and how verifications can be implemented, to ensure that a mocked object’s method has been called.
Up to now, it was not possible to check, which parameters have been passed.

Ensure, that a mocked object has been called with certain parameters

In the current build, I also included the possibility to verify the parameters that have been passed to a mock object’s method.
This is how it works:
First of all, you need to keep track of the mocker object of type ZIF_MOCKA_MOCKER (which means, please do not throw it away 😉 )
By utilizing this mocker object, you can get data about your mocked methods, such as if it has been called with certain parameters or not:

DATA lv_has_been_called TYPE abap_bool.
lv_has_been_called = lo_mocker->method( 'get_delay' )->has_been_called_with(
i_p1 = 'LH'
i_p2 = '300'
i_p3 = sy-datlo
).

For further details, please see report ZMOCKA_DEMO that is shipped with the current release.

Limitations

Only IMPORTING parameters are supported so far, this means no CHANGING parameters can be verified yet.

Mock specific classes with mockA

With mockA it is quite easy to mock interfaces for unit tests. But it is also capable of creating mock objects that are not based only on interfaces, but specific classes. This blog post shows how it works and what needs to be considered.

Basics

Creating such an instance is quite the same as the creation of mock objects based on interfaces. The only restriction that applies is the fact that the class which is to be mocked may not be final class. This is necessary because mockA couldn’t create a subclass to override method outputs.

The classes in the following examples can be found in the mockA package provided at Github.

DATA lo_mocker TYPE REF TO zif_mocka_mocker.
DATA lo_mocker_method TYPE REF TO zif_mocka_mocker_method.
DATA lo_flight_observer TYPE REF TO zcl_mocka_flight_observer.
lo_mocker = zcl_mocka_mocker=>zif_mocka_mocker~mock( zcl_mocka_flight_observer=>gc_name ).
lo_mocker_method = lo_mocker->method( 'observe_flight' ).
lo_mocker_method->with( i_p1 = 'NA' i_p2 = 007 i_p3 = sy-datlo ).
lo_mocker_method->returns( abap_true ).
lo_flight_observer ?= lo_mocker->generate_mockup( ).

Constructor parameters

However, this little example will still fail, as ZCL_MOCKA_FLIGHT_OBSERVER’s constructor expects non-optional IMPORTING parameters. This is an issue which is not existent for interfaces. As you mock already existing implementations, you also need to take care of that.

But that is also no problem at all. Consider the following example that passes some earlier created instances to the constructor. It can be achieved by calling the method PASS_TO_SUPER_CONSTRUCTOR of the mocker instance.
DATA lo_is_in_time_info TYPE REF TO zif_mocka_is_in_time_info.
DATA lo_flight_alert_process TYPE REF TO zif_mocka_flight_alert_process.
*create lo_is_in_time_info and lo_flight_alert_process... (not shown here)
DATA lo_mocker TYPE REF TO zif_mocka_mocker.
DATA lo_mocker_method TYPE REF TO zif_mocka_mocker_method.
DATA lo_flight_observer TYPE REF TO zcl_mocka_flight_observer.
lo_mocker = zcl_mocka_mocker=>zif_mocka_mocker~mock( zcl_mocka_flight_observer=>gc_name ).

lo_mocker->pass_to_super_constructor(
i_p1 = lo_flight_alert_process i_p2 = lo_is_in_time_info ).
*mock some method output (not shown here)
lo_flight_observer ?= lo_mocker->generate_mockup( ).

The example s are also in the mockA package. Take a look at the unit test report ZTEST_CL_MOCKA_MOCKER and the test methods mock_class_with_construc_param, mock_class_with_method_output and mock_intf_with_construc_param.

mockA tutorial – How to create mocks

The previous blog post dealt with the question how fakes can be created using the new open source mocking framework mockA.
Fakes are mocked instances that return specific values when certain methods are called. In comparison to mocks, they do not validate if certain methods have been called or not.
The creation of fakes does not differ from the creation of mocks when you use mockA. Take a look at the setup routine of the unit test report ZTEST_CL_MOCKA_FLIGHT_OBSERVER that is ships with the framework.
In this unit test, a sample flight observer is to be tested. The flight observer depends on two other components, which are an object that provides some flight information as well as an object that processes alerts on specific late flights. The flight observer is determined to get the delay status of some sample flight data and delegate the creation of some alerts to the alert processor conditionally. While the flight information object serves as fake only, as it returns only sample data for specific flights (that is, method inputs), the alert processor serves as mock object that is subject to unit test assertions.
Please note, that MO_ALERT_PROCESSOR_MOCKER is a member attribute which can be used for later use. The created mock object does not need to return any values. This means, the object is only created but no method output is specified.
** Member attributes
* DATA mo_alert_processor TYPE REF TO ZIF_MOCKA_FLIGHT_ALERT_PROCESS .
* DATA mo_alert_processor_mocker TYPE REF TO ZIF_MOCKA_MOCKER.

* create an empty alert backend (we just need to track the number of method calls)
mo_alert_processor_mocker = ZCL_MOCKA_MOCKER=>ZIF_MOCKA_MOCKER~mock( iv_interface = 'ZIF_MOCKA_FLIGHT_ALERT_PROCESS' ).
* this call creates the alert processor mockup
mo_alert_processor ?= mo_alert_processor_mocker->generate_mockup( ).

If a certain method has been invoked on the mock object MO_ALERT_PROCESSOR can be checked later by the following call on its creator.
DATA lv_has_been_called TYPE apa_bool.
lv_has_been_called =
mo_alert_processor_mocker->has_method_been_called( 'ALERT_DELAY' ).

This kind of verification is usually needed in the assert-section of the unit test. Alternatively, you can access the exact method call count by calling this method:
DATA lv_method_call_count TYPE i.
lv_method_call_count =
mo_alert_processor_mocker->method_call_count( 'ALERT_DELAY' ).

And that’s it. Besides the verification of a method call count, no other validation can be carried out against mock objects yet. In future releases, the verification if a specific method has been called with specific values could be implemented. This is one of the top priority functional gaps which exist for the framework right now.

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

mockA released – a new ABAP Mocking Framework

Some good news…

The ABAP Mocking Framework presented last year is now Open Source.
mockA
The namespace has been changed to Z* in order to allow every interested developer to participate in the development of this tool.
Feel free to participate in the development process and visit the project page at Github.
Current Features

  • Mocking of ABAP interfaces and non-final classes
  • Conditional returning of RETURNING, EXPORTING and CHANGING parameters for methods based on specific parameter combinations of IMPORTING and CHANGING parameters
  • You can even define different output each time when the method is called multiple times with the same parameter values
  • raiseable exceptions
  • verification of mocked method call count

How to start

  • Visit us on Github
  • Check Out the daily build and import it to your SAP System using SAPLink
  • As there is no documentation yet, the Unit Test ZTEST_CL_MOCKA_MOCKER describes the features of the tool
  • The Demo report ZTEST_CL_MOCKA_FLIGHT_OBSERVER also demonstrates some features described last year

Functional gaps

  • Verification of mocked method calls against certain expected parameter input
  • Register pattern based method signatures for mocked methods

Credits

Thanks to leogistics GmbH, the formerly internal project is now open source. leogistics has decided to provide it as open source software to strengthen the SAP Netweaver and its ABAP development capabilities, and, of course to allow the community to benefit from this tool and make it even better.

Why should we write clean code?

Dojo

Recently I took part in an architecture dojo. This is an exercise, where a certain simplified example of a program specification is given. The participants are asked to propose an architecture how the task can be solved. Architecture dojos usually do not focus on the code level, rather on a more course grained level dealing with the structure of the program rather than the code itself.
The goal is to present a good architecture in the end after a certain period of time. What makes this architecture good and what makes it bad? The outcome should meet certain requirements like evolvability, testability and the alignment to clean code principles.

The specification

There is OCR software which scans paper documents with document numbers. It produces a file with multiple entries.
One logical line consists of three physical lines and may look like this:
Digits
Each character consists of three horizontal characters over four lines. Only pipes and underscores are allowed and can be arranged to represent a certain number.
The fourth line contains no data, as it serves as delimiter for the next document number.
You will have to write a program that reads this file from a client computer, parses it and outputs the actual document numbers on the screen.
Please keep in mind: In the future, the source where the files are uploaded from may change from client side storage to server side storage. Additionally the solution should be easily testable using unit tests.

Executing the program

Of course the task of this blog post was not to implement a program. But here it is.
This is the sample file content.
Sample File
And this is the output by the program.
sample output

Bringing design principles into play

To achieve the requirements given in the specification, a single monolithic program wouldn’t be an option.
A single program which reads the file, converts and parses it within one huge method, wouldn’t be easily testable.
Additionally, any other source where the file may come from would have to be coded directly into that method. This change would cause a break to the encapsulation.
This brings us to the question how clean code principles might help us to enforce a good architecture.
Especially the following principles should be considered:

  • Single Responsibility Principle (SRP)
  • Open Closed Principle (OCP)
  • Single Level of Abstraction (SLA)

No more buzzwords!

What do all these principles mean? Let’s have a short briefing.

Single Responsibility Principle (SRP)

A class should have only one responsibility. Always try to give the class, that you are currently developing, a description of what it does. If you need to use the word “and”, or you can only hardly cope without using it, there could be a violation to SRP.

Open Closed Principle (OCP)

A class should be open for extensions, but closed for modifications. This usually only works for some kinds of changes, but not for every thinkable future change. A list of what could change with the program, which we need to design in the dojo, is mentioned within the specification.
For example, if the way how the file is going to be accessed changes, the change should not affect existing code in the core program. Every new data source will have to be made available through extension, but not through modification.
But please remember: As often, the list of the above mentioned possible changes might not be a complete one.

Single Level of Abstraction (SLA)

“Each piece of code should talk on a distinctive level of granularity. Don’t mix implementation details with invocation of high-level abstractions. Refactor code to balance the level of abstraction.” (http://lumiera.org/project/background/CleanCodeDevelopment.html)
If we apply this principle to the future design, there should be at least distinct methods to access the file contents, to group the logical lines into sets of physical lines, or to split the logical characters which cover multiple physical lines into distinct 3 character X 4 lines chunks. The calls to these and certain more methods will have to be arranged by another and more course-grained method.

Okay, so what needs to be done?

Let’s get an overview of the different responsibilities of the program. First of all, there will be some kind of file access. When we got the file into the memory, it should be separated into chunks of four lines each. This is another responsibility which actually has nothing to do with how the file is accessed. Finally, each chunk consisting of string lines will need to be separated by another functionality, which extracts the characters out of the chunks. As these characters are still somehow encodes (as every character spans 3 characters x 4 lines in the file contents) there will be another function that parses these characters. In the end, the parsed characters will need to be concatenated and returned by a component which arranges the calls to the described functionalities.

File access

The access to the file contents is a functionality which will be replaced later on by another implementation (client side upload vs. server side upload). This is what is already mentioned in the specification. We decide to implement that each of these functionalities is implemented by a specific class. These classes will need to implement a common interface as callers to these functionalities should not really need to care about how the file access is implemented in particular. The first implementation of this interface will have to read a file from the client computer.
ZIF_OCR_FILE_ACCESS

Lines Separation

Each logical line which represents one account number consists of four physical lines. We will need to split these into chunks of four lines each. This responsibility is specified by another interface.
If any detail relevant for the line separation should change in the future (e.g. if another empty line besides the fourth one is introduced), the caller of this functionality should not really care about what is going on. Instead, we just describe the functionality by an interface which will also need to be implemented by a specific class later on. The output will be TYPE TABLE OF STRING_TABLE (custom type)
ZIF_OCR_LINES_SEPERATOR

Character separation

Each line which consists of four physical lines should be separated into chunks which represent the logical characters (that is, chunks of 3 x 4 characters). So here is another interface which describes this interaction. Character separation will take place for each logical line, so the input will be STRING_TABLE and the output will be another custom type which represents a nested table with logical characters. A logical character representation is TYPE TABLE OF CHAR03, a collection of them is just another nested table of TYPE ZOCR_T_LOGICAL_CHARACTERS.
ZIF_OCR_CHARACTERS_SEPERATOR

Character Parsing

Every logical chunk representing a real character which is relevant for the output, must be parsed.
ZIF_OCR_CHARACTER_PARSER

Who is the organizer?

Of course there should be a class which organizes the calls to the string manipulation and file access components.
Here it is. The interface requires the method to return a list of account numbers in string format.
ZIF_OCR_PARSING_ALGORITHM

The whole picture

What does it look like now? How does the implementer of ZIF_OCR_PARSING_ALGORITHM know all the other components which are to be used?
The answer is “constructor injection”. Every dependency is handed over to the implementer of ZIF_OCR_PARSING_ALGORITHM when the CREATE OBJECT statement to create this instance is executed. These dependencies are instances of specific classes on their own. They implement the already introduced interfaces.
There will be another caller which puts all of these functional bricks together, but for now, this information should be comprehensive enough to form a big picture:
Big Picture

Benefits

This approach of having such small classes might look a little bit strange for someone who developed in ABAP for years. But it has its benefits. The resulting structure is easily maintainable as interfaces hide the implementation details of classes and their sub-components (that is, more fine-grained, other classes). The implementations behind these interfaces can be switched easily without changing existing code within the core parser code.
Additionally, unit tests can be applied quite easy to each of these implementations. Unit tests have the goal to document and test behavior consistently, comprehensible and repeatable. This safes testing efforts when in integration tests and tracks down possible issues with the code to specific classes just by executing the unit within milliseconds.
Writing a testable program and applying unit tests to it usually takes up two to three times of what it would take to write it quick & dirty. But when it comes to testing and when issues start to arise, the test-based approach takes up speed in terms of defect rate and time to localize an error. In the end, it usually safes more time than it costs you to do it properly.