Data-Driven Testing with XLS Example 2: Euro 2012 Web Service

This post covers a very basic sample project (really a single data-driven test case) to illustrate a data-driven testing technique using an Excel file as your test data source.  It's a simplified run-through of the same material covered here; this post is meant to provide an alternative working example.  There is some information in the original post not covered here (in particular, information about working with mixed data types); once you're familiar with the basics of working with the POI API covered in this post, I still recommend checking out the original post, particularly if you have to work with data types in the source sheet other than text.

You can download the sample project and its XLS file here in a single zipped file.  Unzip the files and import the project into soapUI.  You can place the XLS file wherever you'd like, although by default the script expects to find it in a directory called C:\Temp; you'll have to make a corresponding modification to the script if you'd like to put it somewhere else.

To use Excel sheets, you'll also have to extend soapUI's functionality using an external API; we'll be using the Apache POI API, which make it possible to access Microsoft documents (including Excel spreadsheets) from within Java.  First, download the Apache POI solution (the binary distribution) from here and unzip the downloaded file.  After unzipping, copy the main POI jar file (it should look something like "poi-versionnumber-releasedate.jar"; versionnumber and releasedate are placeholders for the actual version number and release date) into soapUI's special directory for external JARs: [SOAPUIProgramDirectory]/bin/ext-- of course, you should replace [SOAPUIProgramDirectory] with the path to the soapUI directory on your computer.  Once the POI JAR is in this directory, you should be able to access its members via import statements in soapUI scripts (note: soapUI may require a re-start before it recognizes the JAR file).

The web service contains information about the Euro 2012 soccer tournament.  We'll be using a data-driven testing approach to test the FullTeamInfo operation, which takes a country name as an input and returns details about that country's team, including players, coaches, etc.  Our source XLS file consists of a short list of country names in one column (which we'll use as a request parameter) and their corresponding coaches in a second column (which should be returned in the response).

If you've read my post on data-driven testing using a csv file, the general approach is the same; we're just using a different file type as our data source.  Our setup script contains code to open our source file and read in the first line; the country name and coach are assigned to properties we defined for the test case.  A test request is sent using the country name and an assertion verifies that the name of the coach returned in the response matches the name we read from the file.  A Groovy test step reads in the next line of the file (as long as the end hasn't been reached) and sends execution back to the test request step, where a new request is sent using the next row of data, etc.

Note that if you want to implement your own data-driven test case, you'll probably want to disable the Abort on Error option as I've done in this example project.  Otherwise, execution of the test case stops as soon as a failure occurs-- for a data-driven test case like this, we want to continue iterating over the loop to try all of our inputs even if one or more inputs fails.  The setting seems to be enabled by default for new test cases; to disable it, right-click on the test case, select Options from the context menu, and uncheck the corresponding checkbox:


Let's look at the various scripts in more detail, starting with the test case setup script:

import org.apache.poi.hssf.usermodel.*

context.rowCounter = 0
def srcBook = new HSSFWorkbook(new FileInputStream("C:\\Temp\\Euro2012.xls"))
def srcSheet = srcBook.getSheetAt(0)
def sourceRow = srcSheet.getRow(context.rowCounter)
testCase.setPropertyValue("Country",sourceRow.getCell(0).getStringCellValue())
testCase.setPropertyValue("Coach",sourceRow.getCell(1).getStringCellValue())
testCase.getTestStepAt(0).setName("FullTeamInfo - " + testCase.getPropertyValue("Country"))
context.srcWkSheet = srcSheet


Let's go through the script line by line; here's line 1:

import org.apache.poi.hssf.usermodel.*

This is the aforementioned import statement-- as I noted before, in order to read from an XLS file we have to extend soapUI's functionality; the import statement makes resources in the POI JAR file (placed in the bin/ext directory earlier) available in our script.

Next we set up a variable to keep track of our place (in terms of rows) in our source spreadsheet-- we'll set this as a property of the context variable so we can maintain its value across test steps and iterations:

context.rowCounter = 0

The next few lines create a workbook object representing our Excel source document and navigate down its structure using get methods, getting objects corresponding to the first worksheet of the workbook (using the workbook object's getSheetAt() method), then the current row in the sheet (using the sheet's getRow() method).  If you put the source xls file in a location other than C:\Temp, you'll want to modify the path in the first line below to point to the file's location on your computer (be sure to use double slashes for your path separators).

def srcBook = new HSSFWorkbook(new FileInputStream("C:\\Temp\\Euro2012.xls"))
def srcSheet = srcBook.getSheetAt(0)
def sourceRow = srcSheet.getRow(context.rowCounter)


Now that we have the first row in the worksheet (in variable sourceRow), we can read in the values of its cells using the getStringCellValue() method and assign them to the Country and Coach user-defined test case properties; we'll use these later in our test request and assertion.

testCase.setPropertyValue("Country",sourceRow.getCell(0).getStringCellValue())
testCase.setPropertyValue("Coach",sourceRow.getCell(1).getStringCellValue())


For readability, the next line re-names the test request step so we can see in the log which country is being used in each iteration.

testCase.getTestStepAt(0).setName("FullTeamInfo - " + testCase.getPropertyValue("Country"))

Finally, the source worksheet object is put into a context property.  This isn't absolutely necessary, but having it handy as a context property saves us a little bit of work in later steps getting another reference to the worksheet.

context.srcWkSheet = srcSheet

We're all set up now for our first test request, having read in the first line of data from our source spreadsheet.  Here's what the test request looks like, using property expansion to use the Country test case property:



FullTeamInfo test request using property expansion with the request parameter

And here's what our XPath assertion looks like to verify that the correct coach is returned in the response:



XPath assertion using property expansion to define the Expected Result

The remaining step in our test case (named ReadNextLine) is a Groovy Script step to prepare for the next iteration and control looping:

import org.apache.poi.hssf.usermodel.*

context.rowCounter++
if(context.rowCounter <= context.srcWkSheet.getLastRowNum()){
def sourceRow = context.srcWkSheet.getRow(context.rowCounter)
testRunner.testCase.setPropertyValue("Country",sourceRow.getCell(0).getStringCellValue())
testRunner.testCase.setPropertyValue("Coach",sourceRow.getCell(1).getStringCellValue())
testRunner.testCase.getTestStepAt(0).setName("FullTeamInfo - " + testRunner.testCase.getPropertyValue("Country"))
testRunner.gotoStep(0)
}


As with the setup script, we need resources in the POI JAR file, so the script starts with the same import statement.  Next we increment the context property we're using to keep track of our row count:

context.rowCounter++

Before we proceed, we have to check if the row value is valid for our source file-- i.e., we have to make sure we're not trying to read beyond the last row of the file.  The remaining lines of the script are wrapped inside an if block; the if statement compares the rowCounter value with the worksheet's last row value, returned by POI's getLastRowNum() method.

if(context.rowCounter <= context.srcWkSheet.getLastRowNum())

Consequently, the lines within the if block are executed only when the value of rowCounter is less than or equal to the total row count of our source worksheet.  The first few lines inside the block should look familiar: they're basically a repeat of the lines in the setup script responsible for getting a row in the worksheet, reading cell values from the row into test case properties, and renaming the request test step for readability:

def sourceRow = context.srcWkSheet.getRow(context.rowCounter)
testRunner.testCase.setPropertyValue("Country",sourceRow.getCell(0).getStringCellValue())
testRunner.testCase.setPropertyValue("Coach",sourceRow.getCell(1).getStringCellValue())
testRunner.testCase.getTestStepAt(0).setName("FullTeamInfo - " + testRunner.testCase.getPropertyValue("Country"))


Now that the next row's values have been read into their corresponding test case properties, the last line passes execution back to the test request step, the first test step in the test case (denoted by 0 using zero-based indexing).

testRunner.gotoStep(0)

The request is sent again and verified using the new values, after which the Groovy Script step runs again, getting the next row of values and sending execution back to the request step, etc.-- our loop is established.  Once we reach the last line of the source file, the if statement in the Groovy Script step will fail, skipping over the gotoStep method and allowing execution to pass on to the test case's teardown script, which consists of a single line to rename the test request step back to its "default" name.  Again, this isn't necessary, but it helps with keeping request inputs clear.

testCase.getTestStepAt(0).setName("FullTeamInfo")

Run the test suite and you should see it send the test request repeatedly, using the different countries specified in the source file as input parameters and verifying that the correct coach (also specified in the input file) is returned for each country.  I've "planted" a deliberate error in the source file, so you should see a failure occur for the test request for Germany:



Test Suite Log output

No comments:

Post a Comment

Please be respectful of others (myself included!) when posting comments. Unfortunately, I may not be able to address (or even read) all comments immediately, and I reserve the right to remove comments periodically to keep clutter to a minimum ("clean" posts that aren't disrespectful or off-topic should stay on the site for at least 30 days to give others a chance to read them). If you're looking for a solution to a particular issue, you're free to post your question here, but you may have better luck posting your question on the main forum belonging to your tool's home site (links to these are available on the navigation bar on the right).