1

我需要使用 Cucumber 和 Java 对我的 REST Web 服务执行负载测试。此 REST Web 服务接受一个名为 id 的字符串输入并返回复杂的 JSON 对象。

我编写了一个 .feature 文件,其中包含在 java 中定义的 Given、When 和 Then 注释。类和注释的骨架定义在下面。

1)功能(UserActivity.feature)

@functional @integration
Feature: User System Load Test
        Scenario Outline: Load test for user data summary from third party UserSystem
                            Given Simultaneously multiple users are hitting XYZ services with an id=<ids>
                            When I invoke third party link with above id for multiple users simultaneously
                            Then I should get response code and response message for all users
                            Examples:
                                | ids |
                                | "pABC123rmqst" |
                                | "fakXYZ321rmv" |
                                | "bncMG4218jst" |

2)LoadTestStepDef.java(特征定义)

package com.system.test.cucumber.steps;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.runners.model.InitializationError;

import com.system.test.restassured.LoadTestUtil;

import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;


public class LoadTestStepDef 
{

    private static Logger LOG       = LogManager.getLogger( LoadTestStepDef.class );
    private String        id        = null;
    private LoadTestUtil service    = null;

    @Given("^Simultaneously multiple users are hitting XYZ services with an a id=\"(.*?)\"$" )
    public void Simultaneously_multiple_users_are_hitting_XYZ_services_with_a_id( String id )
    {
        LOG.debug( "ID {}", id );
        LOG.info( "ID {}", id );
        this.id = id;
    }

    @When( "^I invoke third party link with above id for multiple users simultaneously$" )
    public void invoke_third_party_link_With_Above_ID_for_multiple_users_simultaneously() throws InitializationError
    {
        LOG.debug( " *** Calling simulatenously {} ", id );
        LOG.info( " *** Calling simulatenously {}", id );

        //Create object of service
        service = new LoadTestUtil();

        //Set the id to the created service and invoke method

        service.setData(id);
        service.invokeSimultaneosCalls(10);

    }


    @Then( "^I should get response code and response message for all users$" )
    public void Should_get_response_code_and_response_message_for_all_users()
    {
        LOG.info( "*** Assert for response Code" );
        service.assertHeaderResponseCodeAndMessage();
    }
}

3) LoadTestUtil.java

package com.system.test.restassured;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.concurrent.Callable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.jayway.restassured.path.json.JsonPath;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

import java.util.concurrent.TimeUnit;

public class LoadTestUtil 
{


        private String id = null;
        private int numberofTimes;

        //Create List to hold all Future<Long> 
        private List<JsonPath> jsonResponseList = new ArrayList<JsonPath>();

        //No arg Constructor
        public LoadTestUtil()
        {

        }

        //Set data method to set the initial id
        public void setData(String id)
        {
            LOG.info( "LoadTestUtil.setData()", id );
            this.id = id;
        }

        //This method is used call the REST webservice N times using threads and get response
        public void invokeSimultaneosCalls(int numberofTimes)
        {
            LOG.info( "LoadTestUtil.invokeSimultaneosCalls() - Start" );
            this.numberofTimes = numberofTimes;
            try
            {
                long start = System.nanoTime();



                int numberOfThreads = Runtime.getRuntime().availableProcessors();
                LOG.info("Number of processor available {}" , numberOfThreads);

                //Create pool for the Executor Service with numberOfThreads.
                ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);


                //Create a list to hold the Future object associated with Callable
                List<Future<JsonPath>> futureList = new ArrayList<Future<JsonPath>>();

                //Create new RESTServiceCallTask instance
                Callable<JsonPath> callable = new RESTServiceCallTask(id);

                Future<JsonPath> future = null;

                //Iterate N number of times to submit the callable object
                for(int count=1; count<=numberofTimes;count++)
                {
                    //Submit Callable tasks to the executor
                    future = executor.submit(callable);
                    //Add Future to the list to get return value using Future
                    futureList.add(future);
                }

                //Create a flag to monitor the thread status. Check whether all worker threads are completed or not
                boolean threadStatus = true;
                while (threadStatus) 
                {
                    if (future.isDone()) 
                    {
                        threadStatus = false;
                        //Iterate the response obtained from the futureList
                        for(Future<JsonPath> futuree : futureList)
                        {
                            try 
                            {
                                //print the return value of Future, notice the output delay in console
                                // because Future.get() waits for task to get completed
                                JsonPath  response  = futuree.get();
                                jsonResponseList.add(response);
                            } 
                            catch(InterruptedException ie)
                            {
                                ie.printStackTrace();
                            }
                            catch(ExecutionException ee)
                            {
                                ee.printStackTrace();
                            }
                            catch(Exception e)
                            {
                                e.printStackTrace();
                            }
                        }//End of for to iterate the futuree list
                    } //End of future.isDone()
                } //End of while (threadStatus)

                //shut down the executor service now
                executor.shutdown();

                //Calculate the time taken by the threads for execution
                executor.awaitTermination(1, TimeUnit.HOURS); // or longer.    

                long time = System.nanoTime() - start;

                logger.info("Tasks took " + time/1e6 + " ms to run");

                long milliSeconds = time / 1000000;

                long seconds, minutes, hours;  
                seconds = milliSeconds / 1000;  
                hours = seconds / 3600;  
                seconds = seconds % 3600;  
                seconds = seconds / 60;  
                minutes = seconds % 60;  
                logger.info("Task took " +  hours + " hours, " + minutes + " minutes and " + seconds + " seconds to complete");
            } //End of try block
        catch (Exception e) 
        {
            e.printStackTrace();
        }

            LOG.info("LoadTestUtil.invokeSimultaneosCalls() - jsonResponseList {} " , jsonResponseList);
            System.out.println("LoadTestUtil.invokeSimultaneosCalls() - jsonResponseList {} " + jsonResponseList);
            LOG.info( "*** LoadTestUtil.invokeSimultaneosCalls() - End" );

        }

        public void assertHeaderResponseCodeAndMessage(){

            //Number of response objects available
            int size = jsonResponseList.size();
            LOG.info("Number of REST service calls made = ", size);

            for(JsonPath jsonResponse : jsonResponseList)
            {
                String responseCode = jsonResponse.get( "header.response_code").toString();
                String responseMessage = jsonResponse.get( "header.response_message").toString();

                assertEquals( "200", responseCode);
            assertEquals( "success", responseMessage);

            }
        }
}

4) RESTServiceCallTask​​.java

此类实现 Callable 并覆盖 call() 方法。在 call() 方法中,每次调用都会返回 JsonPath 形式的响应

package com.system.test.restassured;


import static com.jayway.restassured.RestAssured.basePath;
import static com.jayway.restassured.RestAssured.baseURI;
import static com.jayway.restassured.RestAssured.given;
import static com.jayway.restassured.RestAssured.port;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;


import com.system.test.restassured.TestUtil;
import com.jayway.restassured.path.json.JsonPath;
import com.jayway.restassured.response.Response;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

public class RESTServiceCallTask implements Callable<JsonPath>
{

    private static Logger LOG = LogManager.getLogger(RESTServiceCallTask.class);
    private Response  response = null;

    private String id;

    private String environment;
    //private JsonPath jsonPath;

    /**
     * Constructor initializes the call to third party system
     * 
     * @param id
     */
    public RESTServiceCallTask(String id) 
    {

        LOG.info("In RESTServiceCallTask() constructor ");
        this.id = id;

        //Read the environment variable ENV to get the corresponding environment's REST URL to call
        this.environment = System.getProperty("ENV");
        baseURI = TestUtil.getbaseURL(environment);
        basePath = "/bluelink/tracker/member_summary";
        port = 80;
        LOG.info(" *** Environment : {}, URI: {} and Resource {} ", environment, baseURI, basePath);
    }

    //This method is called by the threads to fire the REST service and returns JSONPath for each execution
    @Override
    public JsonPath call() throws Exception
    {
        LOG.info(" *** In call() method ");

        try 
        {
              response = given().headers("id", this.id).log().all().get();
        } catch (Exception e) 
        {
              LOG.error("System Internal Server Error", e);
        }


        String strResponse = this.response.asString();
        LOG.info("Response : {}", strResponse);

        JsonPath jsonResponse = new JsonPath(strResponse);
        return jsonResponse;
    }
}

5)TestUtil.java

该实用程序类用于获取传递的环境对应的 REST URL

package com.system.test.restassured;

import java.util.HashMap;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class TestUtil 
{
    private static Logger LOG = LogManager.getLogger(TestUtil.class);
    private static final Map<String, String> ENVIRONMENT_MAP =  new HashMap<String, String>();

    static
    {
        ENVIRONMENT_MAP.put("LOCAL", "http://localhost:9080");
        ENVIRONMENT_MAP.put("ENV1", "http://localhost:9080");
        ENVIRONMENT_MAP.put("ENV2", "http://localhost:9080");
        ENVIRONMENT_MAP.put("ENV3", "http://localhost:9080");
    }

    public static String getbaseURL(String environment)
    {
        LOG.info("Environment value fetched = {}", environment);
            return ENVIRONMENT_MAP.get(environment);
    }   

}

这里的问题是多线程功能没有得到执行。我使用了 MavenSurefire 插件并尝试了并行类和方法。在这些情况下,上述情况也不起作用。

Cucumber 支持 java 多线程吗?如果是这样,上述特征定义有什么问题?

注意 - 使用独立程序执行相同的任务,并且能够使用 4 个线程运行 10,000 次而没有任何问题。但是无法使用 Maven 运行上述代码 2000 次。用了2000次,系统突然崩溃。

我正在使用 Rational Application Developer 8.5、Websphere Server 8.0 和 Maven 3.x 进行上述设置。

感谢您的答复。

4

0 回答 0