Skip to Content
Technical Articles
Author's profile photo stephen xue

Groovy script developement in Test Driven Mode for SAP CPI

Introduction

Groovy script is one of the main programming languages used in SAP CPI development. The SAP CPI console however doesn’t provide an IDE to easily test and debug the groovy script program.

By using the “debug” / “trace” option in the message monitor, we can get some clues of the program in the runtime. Whereas it is not convenient to supervise all of the wanted variables during the runtime after all. That’s why the gurus have come up with the great ideas as below:

https://blogs.sap.com/2017/10/06/how-do-you-test-your-groovy-scripts/

https://blogs.sap.com/2019/05/28/pimp-my-groovy-boosting-cpi-groovy-developments-with-intellij-idea/

https://blogs.sap.com/2018/05/22/get-groovin-with-your-iflows-groovy-scripting-with-eclipse-for-cpi/

 

It makes the Groovy script program becomes testable in the local IDE.

Take into account that more and more projects are running on the Agile mode and test driven development has been widely used. I’d like to show a case that developing a Groovy script for SAP CPI by using Test Driven Mode.

Sample Case

Overview requirement

The CPI is supposed to expose an API to the client to consume. The endpoint URL is in format as below

https://test.bsn.neo.ondemand.com/http/hello?client=NPL&system_id=e6975e7a-4c7f-11ea-b77f-2e728ce88125&scope=COMPANY&start_date=2020-01-02&redirect_uri=http://remote.com.au/Callback&category=

The Groovy script inside the CPI is to parse all of the Header parameters and all 5 parameters of the client URL and populate them into message body in form of json as below

{
	"client": "NPL",
	"system_id": "e6975e7a-4c7f-11ea-b77f-2e728ce88125",
	"scope": "COMPANY",
	"start_date": "2020-01-02",
	"redirect_uri": "http://remote.com.au/Callback",
	"category": null
}

Possible Story Card for The Groovy Script to be Developed

  • Given

The Client makes a GET operation to the endpoint by using URL

https://test.bsn.neo.ondemand.com/http/hello?client=<client>&system_id=<system_id>&scope=<COMPANY|DISTRIBUTION|PLANT>&start_date=<DATE>&redirect_uri=<http://remote.com.au/Callback>&category=<category>
  • When

The Sroovey script has been executed

  • Then

The payload as below should be set to message body

{
	"client": <client>,
	"system_id": <system_id>,
	"scope": <COMPANY|DISTRIBUTION|PLANT>,
	"start_date": <DATE>,
	"redirect_uri": <http://remote.com.au/Callback>,
	"category": <category>
}

Unit Test Template

here is a Unit Test template for your reference to be used. I will elaborate the detail implementation of each methods included later.

    static void main(String[] args) {
        Initialization()
//GIVEN
        SetHeaders()
        SetBody()
//WHEN
        ExecuteTest()
//THEN
        UnitTestCases()
        DisplayResultToConsole()
    }

method Initialization will create a test class instance;

for GIVEN part, the template will set message header, body by using the testing data;

for WHEN part, the production code will be called;

for THEN part, the unit test cases will be asserted one by one and the result will be displayed;

Design the test cases

As for the test driven development, the test cases is supposed to be designed before the production code development.

In this example case, i will use URL given at the very beginning

https://test.bsn.neo.ondemand.com/http/hello?
client=NPL&system_id=e6975e7a-4c7f-11ea-b77f-2e728ce88125&
scope=COMPANY&start_date=2020-01-02&
redirect_uri=http://remote.com.au/Callback&category='

it has five parameters and the last one, category, is empty

For the test cases, i have come up with two:

  1. Check the hostname plus the endpoint is correct
  2. Check all of the parameter names are correct

These are two test cases developed.

    private static void UT_HTTPURLIsCorrect(payload){
        String uttpurl = 'https://test.bsn.neo.ondemand.com/http/hello'
        assert payload.find{it.key == 'CamelHttpUrl'}.value== uttpurl
    }
    private static void UT_ParemterNameIsCorrect(payload){
        Set parameterList = ["client", "system_id", "start_date", "redirect_uri","category"]
        int i
        payload.each {
            it ->
                if(parameterList.contains(it.key)) {
                    i++
                }
        }
        assert i == 5
    }

After all of the test cases have been asserted, the result(header/body) still needs to be displayed so that it will be more clear for the developer to check.

    private static void DisplayResultToConsole(){
        // Print Headers
        msg.getHeaders().each {
            println it
        }
        // Print body
        println msg.getBody()
    }

 

Positive Test Result

This is the result when a successful test has been conducted.

 

Negative Test Result

In order to make a negative result, let change a Unit Test Case a little bit as below:

and execute the test program again. we will get a result as below:

Production Code

The production code developed is quite straightforward. Here is the source code

package test.com
import com.sap.gateway.ip.core.customdev.util.Message;
import groovy.json.*;

Message processData(Message message) {
    def params = [:]
    def urlParameters = message.getHeaders().get("CamelHttpQuery")
    // Parse all URL parameters into message payload
    urlParameters.split("&").each {
        it ->
            String[] pair = it.split("=")
            params[pair[0]] = (pair as List)[1]
    }

    // Parse all header parameters into message payload
    message.getHeaders().each {
        it ->
            params << it
    }
    message.setBody(JsonOutput.toJson(params))
    message.setHeader('Content-Type', 'application/json');
    return message
}

 

Full version of the Unit Test Template Program

package test.com
import com.sap.gateway.ip.core.customdev.util.Message
import com.sap.gateway.ip.core.customdev.processor.MessageImpl
import groovy.json.JsonOutput
import groovy.json.JsonSlurper

class UnitTest {
// Global Variables
    private final static String TEST_PROGRAM = './src/test/com/ParseURLParameter02.groovy'
    private static String testURL = 'https://test.bsn.neo.ondemand.com/http/hello?client=NPL&system_id=e6975e7a-4c7f-11ea-b77f-2e728ce88125&scope=COMPANY&start_date=2020-01-02&redirect_uri=http://remote.com.au/Callback&category='
    private static Message msg
    
    static void main(String[] args) {
        Initialization()
//GIVEN
        SetHeaders()
        SetBody()
//WHEN
        ExecuteTest()
//THEN
        UnitTestCases()
        DisplayResultToConsole()
    }

    /*----------------------------------Unit Test----------------------------------------*/
    private static void UnitTestCases(){
        def jsonSlurper = new JsonSlurper()
        def payload = jsonSlurper.parseText(msg.getBody());

        UT_ParemterNameIsCorrect(payload)
        UT_HTTPURLIsCorrect(payload)
    }
    private static void UT_HTTPURLIsCorrect(payload){
        String uttpurl = 'https://test.bsn.neo.ondemand.com/http/hello'
        assert payload.find{it.key == 'CamelHttpUrl'}.value== uttpurl
    }
    private static void UT_ParemterNameIsCorrect(payload){
        Set parameterList = ["client", "system_id", "start_date", "redirect_uri","category"]
        int i
        payload.each {
            it ->
                if(parameterList.contains(it.key)) {
                    i++
                }
        }
        assert i == 5
    }
    
    /*---------------------------------Utility Methods-----------------------------------------*/
    private static void DisplayResultToConsole(){
        // Print Headers
        msg.getHeaders().each {
            println it
        }
        // Print body
        println msg.getBody()
    }
    private static void ExecuteTest(){
        GroovyShell shell = new GroovyShell()
        def script = shell.parse(new File(TEST_PROGRAM))
        script.processData(msg)
    }
    private static void SetBody(){
        def payload = [:]
        msg.setBody(JsonOutput.toJson(payload))
    }
    private static void SetHeaders(){
        // Parse URL
        def urlComponents = [:]
        (this.testURL =~ /([^?]*)+/)[0..-1].eachWithIndex{
            it,i->
                switch(i) {
                    case 0:
                        urlComponents [ 'CamelHttpUrl' ] = it [ 0 ];
                        break;
                    case 2:
                        urlComponents [ 'CamelHttpQuery' ] = it [ 0 ];
                        break;
                }
        }
// Set URL parameters
        msg.setHeader('CamelHttpUrl',urlComponents.CamelHttpUrl)
        msg.setHeader('CamelHttpQuery', urlComponents.CamelHttpQuery)
    }
    private static void Initialization(){
        msg = new MessageImpl()
    }
}

 

Conclusion

Given the fact that SAP CPI console doesn’t support runtime testing of Groovy script, the Test Driven Development in the local IDE will be quite effective for CPI development.

 

The source code can be downloaded from here.

 

Assigned Tags

      2 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Eng Swee Yeoh
      Eng Swee Yeoh

      Nice blog post, Stephen.

       

      If you are interested in TDD approach for developing Groovy scripts in CPI, I suggest that you check out Spock. It provides a nice framework which allows you to set up your given/when/then parts as well as nifty result display.

      I’ve written on this in the following blog post (it was on Eclipse before I switched to IntelliJ, but the concept is the same)

      https://blogs.sap.com/2018/01/24/cpis-groovy-meets-spock-to-boldly-test-where-none-has-tested-before/

       

      Have fun!

      Author's profile photo stephen xue
      stephen xue
      Blog Post Author

      thanks, Master. i will have a look.