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

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

主站蜘蛛池模板: 米脂县| 遂溪县| 阿拉善右旗| 交口县| 屏东县| 裕民县| 牟定县| 肇庆市| 建平县| 大理市| 新乡县| 烟台市| 禄劝| 茶陵县| 十堰市| 来安县| 房山区| 织金县| 东海县| 得荣县| 突泉县| 荆门市| 民乐县| 杨浦区| 珠海市| 阿城市| 宾川县| 邯郸市| 沙雅县| 宁晋县| 莱芜市| 安福县| 眉山市| 贵南县| 滕州市| 微山县| 广汉市| 宽城| 翁牛特旗| 汤原县| 西乌珠穆沁旗|