官术网_书友最值得收藏!

  • SoapUI Cookbook
  • Rupert Anderson
  • 1031字
  • 2021-07-23 20:19:20

Looping over CSV file data and driving tests with Groovy

Whether it is for loading test data or writing reports, using external data files can be a key part of automated testing. Typically, you might need to read test data from a file and loop over some test steps until there is no more data. In this recipe, we see how this can be achieved easily using several reusable Groovy TestSteps.

Getting ready

For example, let's say we have a small CSV file of invoice data that we want to use to drive our tests:

1,comp1,100.0,2014-12-01 00:00:00
2,comp2,200.0,2014-12-02 00:00:00
3,comp3,300.0,2014-12-03 00:00:00

You can find this data in <chapter2 samples>/invoice.csv.

We will read each line and extract the values into properties, for example, to do something useful, for example, populating a web service request.

I have provided a completed SoapUI project GroovyFiles-soapui-project.xml in the Chapter2 samples.

How to do it...

I'm going to break this down into three separate Groovy TestSteps: one to read the test data, another to extract it, and another to loop until all rows are processed. Perform the following steps:

  1. First, create Groovy TestStep called LoadAllTestDataFromFile and add the following code:
    context["rows"]=[]
    
    //Change this to the location of your CSV file.
    File testDataFile = new File("/temp/invoices.csv")
    testDataFile.eachLine {content, lineNumber -> 
       context["rows"] << content
    }
    
    //Initialise row counter
    context["currentRowIndex"]=0
    
    return "Loaded ${context["rows"].size()} rows."

    Note

    Before running this code, make sure that the testDataFile variable is set to the correct path.

    There's no need to run this just yet. This step loads all the CSV rows into List and initializes a row counter variable.

  2. Next, create a Groovy TestStep called GetNextRowAndExractValues:
    def currentRowIndex = context["currentRowIndex"]
    
    //Get values from csv row
    def rowItems = context["rows"][currentRowIndex].split(/,/)
    def invoiceId = rowItems[0]
    def invoiceCompany = rowItems[1]
    def invoiceAmount = rowItems[2]
    def invoiceDueDate = rowItems[3] 
    
    //Increment counter
    context["currentRowIndex"] = currentRowIndex + 1
    
    return "Row #$currentRowIndex processed."
  3. In this step, we extract all the fields with a view to doing something useful with the values and increment the row counter.
  4. Lastly, create a Groovy TestStep called LoopIfMoreRows, and add the following code:
    def currentRowIndex = context["currentRowIndex"]
    
    if (currentRowIndex < context["rows"].size) testRunner.gotoStepByName("GetNextRowAndExractValues")
  5. Now, run the TestCase that contains the three Groovy TestSteps, and you should see the following:
    Step 1 [LoadAllTestDataFromFile] OK: took 0 ms 
    -> Script-result: Loaded 3 rows. 
    Step 2 [GetNextRowAndExractValues] OK: took 0 ms 
    -> Script-result: Row #0 processed. 
    Step 3 [LoopIfMoreRows] OK: took 0 ms 
    Step 4 [GetNextRowAndExractValues] OK: took 0 ms 
    -> Script-result: Row #1 processed. 
    Step 5 [LoopIfMoreRows] OK: took 0 ms 
    Step 6 [GetNextRowAndExractValues] OK: took 0 ms 
    -> Script-result: Row #2 processed. 
    Step 7 [LoopIfMoreRows] OK: took 0 ms 

This example doesn't actually use the test data, but this would be an easy next step for us.

Tip

Granular Groovy TestSteps

While the preceding 3 steps could be replaced with a single Groovy TestStep, it can help in reuse and readability if the steps are kept separate and well named.

How it works...

The first step exploits the Groovy File class to read in the invoices.csv file. The Groovy File class is more convenient to use than the standard Java equivalent, and is imported automatically by Groovy. The eachLine method allows us to append (using left shift <<) each full line from the CSV file to a rows collection that is stored in the SoapUI context.

Tip

SoapUI (TestCase) context variable

This holds the state or context that is passed between TestSteps. It is a good place to store properties that are required by subsequent TestSteps. Properties added to the context object are lost when the tests finish. In basic terms, the context object is an implementation of java.util.Map, but the actual implementation of the context object is dependent on how you are running the TestStep:

WsdlTestRunContext is used when the TestStep is run as part of a TestCase.

MockTestRunContext is used when you run a TestStep individually.

SecurityTestRunContext is used when the TestStep is run as part of a security scan—see the Scanning web service security vulnerabilities recipe from Chapter 7, Testing Secured Web Services.

There is also a mock context object of type WsdlMockRunContext – see Chapter 3, Developing and Deploying Dynamic REST and SOAP Mocks

We also add currentRowIndex to the context object to keep track of the current row as we iterate through the TestSteps for each row.

The GetNextRowAndExractValues Groovy TestStep extracts the current row from the context and splits the row string by a comma to get an array of field values. Finally currentRowIndex is then incremented and the text Row #$currentRowIndex processed is returned just to provide some debugging output in the TestCase window. It's inside the GetNextRowAndExractValues Groovy TestStep that we could use the invoice CSV values (extracted to variables invoiceId, invoiceCompany, invoiceAmount and invoiceDueDate) to test something or alternatively pass them to another TestStep, for example, use them to populate a web service request (see below example).

Lastly, the LoopIfMoreRows TestStep checks whether there are any rows left, and if so, uses the tesRunner.gotoStepByName() method to repeat the GetNextRowAndExtractValues TestStep.

There's more...

Building on the previous example, the invoice CSV values could be used in a request for a test web service call. To do that, we would need to put the invoice values somewhere where we can accesses them from a subsequent REST Test Request TestStep or (SOAP) Test Request TestStep.

The context object is a good place to set and get TestStep properties and can be used to pass the 'state' between TestSteps.

So, if we inserted the previous test steps around the last chapter's invoice CRUD service's POST REST Test Request TestStep like the one shown in the following screenshot:

There's more...

Then, we can add the following lines of Groovy just after extracting the values in GetNextRowAndExtractValues:

//Create these context properties for use as parameters in the subsequent test steps
context["invoiceCompany"]=invoiceCompany
context["invoiceAmount"]=invoiceAmount

Then, we can access these context properties using the ${property} syntax in the request body of the POST REST Test Request TestStep to create an invoice:

{"Invoice": {
   "companyName": "${invoiceCompany}",
   "amount": "${invoiceAmount}"
}}

Tip

Context property scope

Unlike other SoapUI object properties for example project level properties, context object properties do not require a #scope qualifier when referenced directly using the Property Expansion syntax as in the above example. For examples of how to reference other types of property in using the Property Expansion syntax see http://www.soapui.org/scripting---properties/property-expansion.html.

Running these steps will then call the invoice CRUD service's POST method for each row of CSV invoice data. To see this working, start the service implementation (see the Generating SoapUI tests with REST discovery recipe of Chapter 1, Testing and Developing Web Service Stubs With SoapUI, for more info) and take a look at Invoice-CRUD-Project-soapui-project.xml in the Chapter 2 samples.

If you need to work with JSON or XML file data, then take a look at the Groovy JSON and XML Slurpers (see the following links). They are easy to use and should take care of your parsing needs.

See also

主站蜘蛛池模板: 海盐县| 香格里拉县| 平塘县| 沁阳市| 武宁县| 抚远县| 厦门市| 内丘县| 黔西| 盈江县| 荥阳市| 塘沽区| 古蔺县| 永吉县| 汽车| 雷波县| 兰考县| 江华| 赤壁市| 大连市| 白朗县| 泰顺县| 巴塘县| 玉环县| 保康县| 德化县| 临桂县| 隆德县| 金坛市| 治县。| 高台县| 利辛县| 邹平县| 潢川县| 万盛区| 西畴县| 扎兰屯市| 赤峰市| 金华市| 乌兰浩特市| 铜川市|