Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Venugopal
Product and Topic Expert
Product and Topic Expert
4,648

A process model contains many artifacts which require human/system interaction to complete the end to end process execution. This blog explain how to write eclipse based JUnit tests to automate BPM process model tesing.

Restfuse(http://developer.eclipsesource.com/restfuse/) and Selenium(http://docs.seleniumhq.org/) are the two open source frameworks  used to automate the process model testing.Together with these frameworks the RESTful services of BPM public apis and Apache CXF framework are used .

Restfuse is a Junit extension to test RESTful services. A Restfuse based test uses annotations to define RESTful service url ,Request type, Authentication and content and its type. It is not required to deploy the tests to the BPM server. The test run like any other JUnit test in eclipse.

Restfuse provides a possibility for callbacks and polling in a declarative manner. It also offers dynamic request manipulation at the request header level.

This blog explains how  BPM process model testing can be automated by creating a new process instance and process all the human tasks of the process model and check the completion of the process. The basic requirements to build such tests are the following.

1.      1. SAP Netweaver BPM 7.31

2. RESTful services of BPM (http://scn.sap.com/community/bpm/blog/2011/10/27/restful-service-for-netweaver-bpm)

3.      3. Apache CXF framework (http://cxf.apache.org/)

4.      4. Restfuse (1.2)open source library from eclipse http://developer.eclipsesource.com/restfuse/

       https://github.com/eclipsesource/restfuse/blob/master/build/com.eclipsesource.restfuse.target/restfu...

  5. Selenium open source library from Selenium( http://docs.seleniumhq.org/docs/03_webdriver.jsp#introducing-webdriver)

6.      6. Harmcrest open source library from eclipse(http://hamcrest.org/)

     http://download.eclipse.org/tools/orbit/downloads/drops/R20110523182458/repository

7.         JUnit 4.10 from eclipse.

How to setup the test landscape

1.    1. Deploy the BPM RESTFul services in the JEE system.

     Down load the binaries from the SCN code exchange . The RESTful services can be enhanced to meet the various requirements of the test.

     http://scn.sap.com/community/bpm/blog/2011/10/27/restful-service-for-netweaver-bpm

2.Download and deploy the Apatche CXF framework as explained in the blog

     https://cw.sdn.sap.com/cw/message/86851#86851

2.    3. Down load the eclipse Restfuse 1.2 from

      https://github.com/eclipsesource/restfuse/blob/master/build/com.eclipsesource.restfuse.target/restfu...

     Build the sources in the Developer studio and package the class files in a jar file.

3.    4. Down load the Restfuse dependent libraries from

http://download.eclipsesource.com/technology/restfuse/restfuse-1.1.1.zip     http://download.eclipsesource.com/technology/restfuse/restfuse-1.1.1.ziphttp://download.eclipsesource.com/technology/restfuse/restfuse-1.1.1.zip

     (You need to use Restfuse 1.2  version in order to use the dynamic path segment feature to pass request parameters to the REST service.)

How to write a Junit test to automate a process model

The following annotations are required at the Junit class level

@RunWith( HttpJUnitRunner.class)

Public class bpmProcessModelTest {

      

       @Context private PollState pollState;

      

       @rule public Destination destination = new Destination(this,"http://hostname:port/" );

      

       @Context private Response response;

The Response object will be injected after every request send to the BPM system.

Inorder to have provide the request paramter to the destination URL , you have to define a function which will be called before executing each test.

for eg: 

@rule public Destination destination = getDestination();

In the implementation of the getDestination you could process the request URL .

for eg:

Destination dest =  new Destination(this,"http://servername:port" );

RequestContext context = dest.getRequestContext();

context.addPathSegment("pdefid",processdefid);

The above code snippet can be used to provide the process definition id to retrieve the start event of the process.

Test 1:  Get Process Definition of a Process model

The Path parameter provides the DC Name, Vendor Name and Process Model name to retrieve the process definition id of the process model. The header annotation define the response media type as Json model type.

@HttpTest(method = Method.GET,headers = {@Header(name = "Accept", value = "Application/Json") } ,authentications=@Authentication(type=AuthenticationType.BASIC,user="userid",password="@@@@"), path = "/bpm/bpemservices/processdefinitions?vendor=demo.bpm.test&dcName=customuiprocess&processName=simpleTestProcess")

       public  void getProcessDefintion()

       {

           String s = response.getBody();

          Object obj = JSON.parse(s);

          String pDefId = null;

           if(obj instanceof Map )

     {

             Map m = (Map)obj;

             Object ob = m.get("ProcessDefinitions");

                  if(ob instanceof Map)

        {                   

           Map m1 = (Map)ob;

                        if(m1.get("ProcessDefinition") instanceof Map)

           {

               Map m2 = (Map) m1.get("ProcessDefinition");

               pDefId = (String) m2.get("id");

                      }

        }

      }

           

      com.eclipsesource.restfuse.Assert.assertOk(response);

            

   }

Test 2: Get Process Start event of a process definition

Get the start event id of a process definition by providing the process definition id in the request url as a parameter.

@HttpTest(method = Method.GET,headers = {@Header(name = "Accept", value = "Application/Json") } ,authentications=@Authentication(type=AuthenticationType.BASIC,user="userid",password="@@@@@"), path = "/bpm/bpemservices/processstartevents?processDefinitionId={pdefid}")

       public void getProcessStartEvent()

    {

            String s = response.getBody();

             HashMap obj = (HashMap)JSON.parse(s);

            HashMap events = (HashMap) obj.get("ProcessStartEvents");

            HashMap event = (HashMap) events.get("ProcessStartEvent");

            eventId = (String) event.get("id");

      com.eclipsesource.restfuse.Assert.assertOk(response);

     } 

Test 3: Get Process Start Event Schema

Get the schema of the process start event. The process start event schema is required to define the input data to create an instance of the process.

@HttpTest(method = Method.GET,headers = {@Header(name = "Accept", value = "Application/xml") } ,authentications=@Authentication(type=AuthenticationType.BASIC,user="userid",password="@@@@"), path = "/bpm/bpemservices/processstartevents/{eventid}")

       public void getProcessStartRequestSchema()

       {

             String s = response.getBody();

             com.eclipsesource.restfuse.Assert.assertOk(response);

         

       }

Test 4: Create a process Instance

The Http Post method will send the content together with the request and get the process instance as response. The file attribute determine the input data which is stored in the class path of the test.

@HttpTest(method = Method.POST, file="data.xml" ,headers = { @Header(name = "Accept", value = "Application/json"),@Header(name = "Content-type" , value = "Application/xml") } ,authentications=@Authentication(type=AuthenticationType.BASIC,user="userid",password="@@@@"), path = "/bpm/bpemservices/processstartevents/{eventid}")

       public void createProcessInstance()

       {

             String s = response.getBody();

             HashMap obj = (HashMap)JSON.parse(s);

                    HashMap processInstance = (HashMap) obj.get("ProcessInstance");

             com.eclipsesource.restfuse.Assert.assertOk(response);

                         

       }

Test 5: Get all tasks of a process instance

The @Poll annotation will retry the method twice with 5 seconds interval inorder to ensure that the tasks are created .

@HttpTest(method = Method.GET,headers = { @Header(name = "Accept", value = "Application/Json") } ,authentications=@Authentication(type=AuthenticationType.BASIC,user="userid",password="@@@@"), path = "/bpm/bpemservices/taskinstances/ProcessInstance/{processinstance}?status=READY&status=RESERVED" )

       @Poll( times = 2, interval = 5000 )

       public void getTaskInstanceOfProcess()

       {  

             Object[] taskAbstractList = bpmjsonhelper.getTasks(response);

                            if(null != taskAbstractList )

             {

                             int size =  taskAbstractList.length;

                             for(int i = 0; i < size; i++)

               {

                   HashMap taskAbstract = (HashMap)taskAbstractList[i];

                   String taskid = (String)taskAbstract.get("id");

                   String taskName = (String) taskAbstract.get("name");

                         

                 }

}

// the number of polling interval defined at the @Poll annotation

            

               if(pollState.getTimes() == 2)

        {

            com.eclipsesource.restfuse.Assert.assertOk(response);

         }

            

       }

Test6: Claim & Completion of a Task

    @HttpTest(method = Method.PUT,content ="{x=1}",headers = { @Header(name = "Accept", value = "Application/json"),@Header(name = "Content-type" , value = "Application/json")} ,authentications=@Authentication(type=AuthenticationType.BASIC,user="userid",password="@@@@"), path = "/bpm/bpemservices/taskinstances/{taskinstance}?action=CLAIM")

      public void claimtestTask()

      {

           String s = response.getBody();

            com.eclipsesource.restfuse.Assert.assertNoContent(response);

                 

      }

     

The file attribute determines the task input data  and the file should be in the class path.

    

@HttpTest(method = Method.PUT,file="mytaskData.xml",headers = { @Header(name = "Content-type" , value = "Application/xml")},authentications=@Authentication(type=AuthenticationType.BASIC,user="userid",password="@@@@"), path = "/bpm/bpemservices/taskinstances/{taskinstance}?action=COMPLETE")

      public void completeMyTask()

      {

           String s = response.getBody();

            com.eclipsesource.restfuse.Assert.assertNoContent(response);

      }

Test 7:  Comletion of a Task using Task Execution UI

The REST call provide the task execution URL and selenium webdriver is used to open the task exectuion UI and complete the task.,

@HttpTest(method = Method.GET,headers = { @Header(name = "Accept", value = "Application/Json") } ,authentications=@Authentication(type=AuthenticationType.BASIC,user="userid",password="@@@@"), path = "/bpm/bpemservices/taskinstances/taskinstance/{taskinstance}" )

public void CompleteMyTask()

{

   com.eclipsesource.restfuse.Assert.assertOk(response);

   String s = response.getBody();

   WebDriver webdriver = new FirefoxDriver();

   webdriver.get(s);

   WebElement element = webdriver.findElement(By.name("j_username"));

   lement.sendKeys("userid");

   element.sendKeys(System.getProperty("username"));

   WebElement element2 = webdriver.findElement(By.name("j_password"));

   element2.sendKeys("@@@@");

   WebElement elementForm = webdriver.findElement(By.name("logonForm"));

   elementForm.submit();

   webdriver.get(s);

 

  WebElement taskCompletion = webdriver.findElement(By.id("FDOEEFPDBOMAACHH.TestTaskComponentView.TestTaskCompleteEvent"));  

   taskCompletion.click();

   webdriver.close();

}

Test:8 Process Completion

@HttpTest(method = Method.GET,headers = { @Header(name = "Accept", value = "Application/Json") } ,authentications=@Authentication(type=AuthenticationType.BASIC,user="userid",password="@@@@"), path = "/bpm/bpemservices/processinstances/{processinstance}?status=COMPLETED" )

@Poll( times = 3, interval = 5000 )

public void CheckProcessStatus()

{

       if(pollState.getTimes() ==3)

       {

        String s = response.getBody();

        com.eclipsesource.restfuse.Assert.assertOk(response);

        }

  

}