Technical Articles
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:
- Check the hostname plus the endpoint is correct
- 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.
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!
thanks, Master. i will have a look.