Let's begin with an example.Below method has one function module dependency and one method external method dependency.The Class having this method is CUT(Code Under Test).The aim of the ABAP unit is to validate the code residing in this method,not to validate the code of the dependent function module / other method.
As per the test double framework, to segregate the dependency, a local interface(LIF) needs to be introduced.Then local class (LCL)needs to be introduced based on the interface.This local class will be called during the productive call.
Additionally during the test run,another class"Test double" will be called,This "Test double" (LTD) class also needs to be developed based on the same interface(LIF).So the trick is that during the test run,there is no dependency on the external FM/ methods instead the test double (LTD) will provide the necessary output as LTD needs to be developed keeping all the positive /Negative scenario which needs to be validated.
Productive run Vs Test run
Below are the steps which needs to be followed.
1.Identify the class(Class Under Test) and method for which the ABAP unit test to be written.
2.Identify the Dependency on other Function Module (FM), methods.
3.Segregate dependency by introducing a local interface .-All dependent FM and method’s signature needs to be added to the Interface method.
4.Introduce a local class type referring to the local interface and add the interface method signature.
5.Add the code to call of dependent FM, Method inside local class method by adjusting the Importing,exporting, changing variable and exceptions.
6.Create a Private member attribute of type the local interface .
7.Constructor Injection : Create a new instance of the local class and assign it to the Private member inside the constructor of the CUT.
8.Replace the calling of depended FM with the above private member in side the Method of CUT .
9.Replace the calling of depended method with the above private member in side the Method of CUT .
10.Create a local test double class ( starts with LTD) by implementing the Local interface and Manipulate the output of the method as needed.
11.Define a Local test Class with DEFINITION DEFERRED and add DEFINITION LOCAL FRIENDS with CUT and Implement blank interface method in the local test class and also add the methods for TESTING using key word FOR TESTING.Implement the testing scenarios in the testing method and validate the result with assert.Also assign the member attribute of CUT to the local test double class.
12.Create a local test class for the dependent local class and just hit the dependent method to increase the branch coverage . Do not add asset statement . The intention is not to validate the result of the dependent class.
Let's discuss each step in details.
Identify Class Under Test,Dependency
Segregate dependency using Interface
Private member and Constructor
Replace Fm Dependency
Replace method dependency
Local test double class
Local Test Class with Positive and Negative scenarios
At this stage , all the classes which are mentioned in the Second Image (Productive run Vs Test run) are implemented.
Let's Run the ABAP unit test with coverage.Here the local class(LTCL), which has all the dependent productive code , is showing the coverage as 0.00.To increase the coverage , we need to create another local test class .
Local class coverage
Local test double for Local test class
Below is the image of all the classes including the Second local test class (LTC_sanity_test).
To increase the coverage test class and Local test double class can be enhanced further.Even multiple test double classes can be introduced based on the requirement for example positive , negative, validate exception. If the main class(CUT) is a static class, it has to converted to instance class.
As I faced some challenges to write ABAP UNIT this way at initial phases ,and over the period of time ,I have gained some experience on this approach, thought of sharing this with a larger community, Hence your feedback is important.