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: 

Automated Unit testing: Mock a private method

p_vanalphen3
Explorer

Hello all,

I am using Automated Unit testing a lot. All methods i create are now supported by those unit tests.

At the moment i am struggling if it is possible to MOCK a private method. What i want to achieve is that i can simply say that the outcome of a private method must have THAT value. Of course i can achieve this by programming it, but that means a lot of coding which is kind of redundant if you could simply say, outcome of private method is this.

For public methods used within the method i am able to achieve this by using a self reference which is a testdouble.

I hope my question is clear and that there is a solution for this. it would safe me a lot of coding.

Kind regards,

Peter van Alphen

11 REPLIES 11

pokrakam
Active Contributor
0 Kudos

Interesting question. There are a couple of approaches:

- Perhaps there is perhaps another class trying to get out? It's quick enough to refactor a method out into a local or global class that can be mocked

- Make the method protected and have a mock subclass (or even the test class itself can be a subclass). The method can then be redefined. You do need to be a little careful here, some people have a tendency to let the constructor do too much which could cause issues.

Note, if you have a dedicated mock subclass, I would still define it as FOR TESTING, as it ensures only nonproductive use.

Sandra_Rossi
Active Contributor

You mean, how to access a private member of the global class from a test class?

Solution, declare the test classes as friends of the global class, in the block of test classes:

CLASS testclass1 DEFINITION DEFERRED.
CLASS testclass2 DEFINITION DEFERRED.
CLASS globalclass DEFINITION LOCAL FRIENDS testclass1 testclass2.

CLASS testclass1 DEFINITION FOR TESTING ...
  ...
ENDCLASS.
CLASS testclass2 DEFINITION FOR TESTING ...
  ...
ENDCLASS.

CLASS testclass1 IMPLEMENTATION.
  ...
ENDCLASS.
CLASS testclass2 IMPLEMENTATION.
  ...
ENDCLASS.

p_vanalphen3
Explorer
0 Kudos

sandra.rossi ,this is not what i ment.


I write a unit test method for the public method and i want to control the output of the private method (basicly stub it) without knowing how the logic is of this private method.

0 Kudos

Please use the COMMENT button for comments, questions, adding details, replying to OP comment, etc., ANSWER is only to propose a solution, dixit SAP text at the right of the answer area.

0 Kudos

without a real example is difficult to explain.

But, for my personnal experience, all the private methods have to switch to a new class, where it will be public method. And you finaly just have to mock the new class.

0 Kudos

ok. let me try to explain the situation.

I have this class

SPAN { font-family: "Courier New"; font-size: 10pt; color: #000000; background: #FFFFFF; } .L0S31 { font-style: italic; color: #808080; } .L0S32 { color: #3399FF; } .L0S52 { color: #0000FF; } .L0S55 { color: #800080; }

CLASS lcl_class DEFINITION
FINAL.

PUBLIC SECTION.

METHODS this_one_will_have_ut
IMPORTING iv_city TYPE string
RETURNING VALUE(rv_signal) TYPE string.

PRIVATE SECTION.

METHODS private_i_want_to_stub
IMPORTING iv_city TYPE string
RETURNING VALUE(rv_tempature) TYPE string.
ENDCLASS.


CLASS lcl_class IMPLEMENTATION.

METHOD this_one_will_have_ut.

DATA(lv_tempature) = private_i_want_to_stub( iv_city ).

IF lv_tempature < 0.
rv_signal = |FREEZING|.
RETURN.
ENDIF.

IF lv_tempature < 30.
rv_signal = |NORMAL|.
RETURN.
ENDIF.

IF lv_tempature > 29.
rv_signal = |TOO HOT|.
RETURN.
ENDIF.


ENDMETHOD.

METHOD private_i_want_to_stub.

" Call here the API and tons of database selects etc to get the temp of the city

ENDMETHOD.

ENDCLASS.

I want to write a unit test to check the outcomes of the public method. What i dont want todo is to manage all the dependend object in the private class, but i want to control the outcome in the unit test. For example Unit test 1, just give 25 as return value of the private method. and i can check if the text = NORMAL

I hope this clarifies it a bit.

0 Kudos

Again p.vanalphen3, you seems to violate segregation of responsibility.

If you want to have clean Abap Unit, you need to follow as best the Clean Code GitHub - Clean Code

The minimum is to separate the extraction of the data from the management of the data. You must have a dedicated class for the extraction of the data. You should have a Factory to access this class ( to remove the dependency between the two class ). And you should have interface for all your class.

This looks like boring part of the code, but it will simplify your Abap Unit. Everything are linked, if you have simple class and simple method your test will be simple ...

And if you wonder why you need a dedicated class for the data extraction, just imagine tomorow, the data are stored in other tool, with an odata service to access it. Do you really need to rewrite ALL the program related to these data ? why ? the logic is not the same ? Do you really need to write several time the same code to get the same data ? is it not a loose of time to correct this ?

And if you think the data will never change, start a S/4 upgrade project. It is amazing the number of code to be changed just because one data has changed.

if you need example of what you could do to follow clean code, we could wrote a little example

0 Kudos

frdric.girod Thanks for your remarks, but this explanation was not relevant for my question. Now i gave ofc the example that the private method was doing DB selects or anything. But how to stub this one if it is just a PRIVATE helper method to perform something in my class.

And even in my example with DB selects etc, lets say i have a separate class which is my DOA (database object agent), but i dont want to setup this in every unit test, therefore i would like to have a stub possibility of my PRIVATE method.

0 Kudos

p.vanalphen3, I am sorry again, but this is a not logical request.

First of all, Abap Unit should test only public method. Private method is the internal mechanism. Private method should be able to change without impacting Abap Unit. This is one of the most important rule you try to violate.

And again, if your method strongly depend to another method, this method should be a public method of another class.

I understand this is not your request, but I am sorry, the solution is not to find an answer to your request, but to change your request.

And when you have a separated class, you could easily create a Mock. Are you confortable with Mock usage ? Do you need help ?

Maybe an example wil be more clear than my english explanation 🙂

Sandra_Rossi
Active Contributor
0 Kudos

Sorry. Forget my last comment.

Many ways to do it. Usually private methods don't need to be mocked because they should be simple, no need to test them. If it's a complex method, create a class/interface to support this method, it's then easy to call the method of the instance.

manuish02
Explorer
0 Kudos

If I understand correctly the problem is your private method and public method is in the same class and somehow without executing the actual implementation of the private method you want to stub it out. I dont think I have found a way to do this. The problem is more serious when you have external Code(FM/BAPI?DB callls) call inside the private method. The only way I get around this refactor the private method to keep it simple and take out those external dependencies into an interface and use ATD framework to mock them out.

Having said that it doesn't solve the problem of having to set up the data in a very particular way so you know what you would get out of the private method as output.

In testing frameworks (JEST for java script) I have seen this capability and minimizes the coding effort to mockout the data a lot.