SoapUI with BDD (Cucumber)

Background

Web Service is a way to publish your application over internet and enable other applications to access functions provided by it.
With web service, one could reuse the existing applications, instead of developing the same application over and over again. For example, there are some typical web services such as currency conversion, weather reports, or even language translation.

Web services can also help to solve the interoperability problem by giving different applications a way to link their data. With Web services you can exchange data between different applications and different platforms.

SOAP is a simple XML-based protocol to let applications exchange information over HTTP by exposing an interface defined in Web Services Description Language (WSDL). Other applications can interact with Web service using its WSDL interface. Web Service Functional Testing ensures that your web service is functionally correct.

SoapUI is a popular web service testing tool to create set of request automatically and comparing the result with the expected output.

Prerequisites

Before start, you need to install JDK, Eclipse, Maven and SoapUI Pro. Selenium and Cucumber could be installed by maven automatically with a pom.xml, which will be covered in part 3.

Version:

Create a SoapUI Function Test Case

There are a lot of public web services if search on the internet with “public web service”. In this demo, a weather web service will be used to test.
The WSDL used in this article is: http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL. By open this link, you will find there is a list of operations defined in the WSDL, such as “GetWeatherInformation”, “GetCityForecaseByZIP” and “GetCityWeatherByZIP” as below.
In the demo, we will test one of the operation named as “GetCityWeatherByZIP” by creating a test case and setting properties by groovy script.
wsdl.png

Create a SOAP project

Click on the “File->New SOAP Project” menu to launch the create project dialog.

Then input the WSDL into the “Initial WSDL” text field.

After clicking “OK” button, the sample requests for all operations defined in the above WSDL will be generated in the project as below.

Run the generated request

Click on the request under the getCityWeatherbByZip operation, input any zip code in USA, for example: 98004 (Bellevue) in the left request panel. Then clickto send request to the server. The weather information of Bellevue will be returned as below.

Create test steps

Now, you could add the request into a test case as a test step. If there is no test case or test suite, by adding the request into a test case, the test suite and test case will be generated automatically.

The test case will look like this:

Create project properties

Now, we will start to customize the test case. Instead of hard coding the zip code, we could parameterize it as a property. Click on project node, then switch to the “Custom Properties” tab to add three properties, named as “usePropertyFileFlag”,”zipCode” and “city” like following.

Add properties into the test steps

Double click on the test step ” GetCityWeatherByZIP – Request 1″, on the request panel, click on the “Form” tab, and click add data button, and choose the property “zipCode”.

 Add assertion into the test steps

On the response panel, click on the outline tab, and right-click on the city node to add an assertion for content using the property “city”.
Note: If the response panel is empty, you could click the run button to send the request firstly, then the response xml will be shown like following.

You could click the “Add Assertion”button to add more assertions into the test step like following.

Then click the run button to verify the test case works well. Every assertion should pass with green.

Use groovy scripts to set properties

Now we will try to use various zip codes to verify the “GetCityWeatherByZIP” request. There are several approaches to accomplish task. For example, using the DataSource and DataSource Loop feature. You could refer to SoapUI tutorial about this implementation.
Here, instead of using DataSource, we will try to store the zip code in a separated property file and pass the values into the test case while running. A groovy script will be used to accomplish it. SoapUI supports using groovy scripts to create customized test steps or setting up, tearing down steps for the whole test case or test suite.

 Create a groovy script in the test suite setup

Click on the setup tab in a test suite, and add your setup script in the panel like following. The script will create a “zipcode.txt” property file if it does not exist.

Source Code
def usePropertyFileFlag = context.expand( '${#Project#usePropertyFileFlag}' )
log.info("--------------------------"+usePropertyFileFlag)
if (usePropertyFileFlag.equalsIgnoreCase("true")){
Properties properties = new Properties();
File f= new File("c:\\sning\\zipCode.txt");
if (!f.exists()) {
f.createNewFile();
properties.setProperty("zipCode", "35594");
properties.setProperty("city", "Winfield");
properties.store(new FileOutputStream(f), "writing the properties");
}
}
Clickto run this step, and you will find the file “zipcode.txt” has been created successfully.

Create a groovy test step in the test case

Then open the test case, click the “create a new groovy script test step” button to create a groovy test step named as “SetProperties”. This groovy script will read the property file “zipcode.txt” and pass the property into the test case.

Source Code:
def usePropertyFileFlag = context.expand( '${#Project#usePropertyFileFlag}' )
if (usePropertyFileFlag.equalsIgnoreCase("true")){
    props = new java.util.Properties()
    fis = new FileInputStream ("C:/sning/zipcode.txt")
    props.load (fis)
    testRunner.testCase.testSuite.project.setPropertyValue( "zipCode", props.getProperty ("zipCode") )
    testRunner.testCase.testSuite.project.setPropertyValue( "city", props.getProperty("city") )
}

Run the test suite

Now, click the run button on the test suite, the test case will run successfully.

Switch to the “TestSuite Log” tab, double click on the Step 2, you could see the request and response message like following. Both of them are using soap envelope.

 Generate a test report by SoapUI

Click the “Creates a Report for this item” button to generate a predefined SoapUI test report.

Now, a SoapUI function testcase has been created successfully. Before we move on to other parts, please save the project as WeatherSoapTest-soapui-project.xml. All of the test steps and test case definitions and groovy scripts will be stored in this project xml file, which will be used in the following steps.

Integrate with Selenium and Cucumber

Now, instead of only using a static property file to test a specific zip code, we need to test the request with various zip codes dynamically. In this article, we will use Selenium to fetch and parse the zip codes and cities from following website, and pass them into SoapUI test case to verify: http://www.phaster.com/zip_code.html.

Create a project with Maven

If it is the first time you use eclipse and maven together, you must add the maven repository path to eclipse by running the command below, and restart eclipse if it is open.

mvn -Declipse.workspace=<path-to-eclipse-workspace> eclipse:add-maven-repo

Create a default maven java project

Run following commands in maven to create a java project named as “WeatherService”.

mvn archetype:generate -DgroupId=com.example -DartifactId=WeatherService -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Update the pom.xml

Change the directory to the WeatherService folder just created by above command, and update the dependencies relevant with SoapUI, Selenium and Cucumber. Following is the whole content of the pom.xml.

Note that the highlighted ones are for SoapUI.

Install the dependencies

Then run the following comands to install all the dependencies.

cd WeatherService
mvn clean install
mvn eclipse:eclipse

Import the project into eclipse

Now, you could import the “WeatherService” project into your eclipse workspace by click “File->Import” menu from Eclipse. Then choose “General->Existing Projects into Workspace”.

After clicking finish, you will see the project like this.

Import the SoapUI project file into the java project.

Create a resource source folder like src/test/resources, and copy paste WeatherSoapTest-soapui-project.xml into the resources folder. You could refer to the Appendix I for the details content of the WeatherSoapTest-soapui-project.xml.

  2

Create a Cucumber Feature File

Now, we will use Cucumber to create a feature file in the resources folder. The scenario will look like following.

 

Feature: 

As weather web service user

I will be able to get the weather information by the predefined operations in the WSDL

@getWeatherByZipcode

Scenario: Get the city weather information by zipcode

Given I have a list of zipcode

When I use the weather service to get the weather information

Then the information should be found successfully

Create a Cucumber JUnit Test Case

Create a Cucumber JUnit test runner like following and run it. You will get a list of missing methods displayed in the console.

package com.example;

import org.junit.runner.RunWith;

import Cucumber.api.CucumberOptions;

import Cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)

@CucumberOptions(features = “src/test/resources/”, tags={“@getWeatherByZipcode”},format = {“pretty”, “html:build/Cucumber -report”,”json:build/Cucumber -json-report.json”})

public
class RunCukesTest {

}

Create a JUnit test case and copy paste the missing methods into it like following.

 

Source Code:

package com.example;

import static org.junit.Assert.*;

import Cucumber.api.PendingException;

import Cucumber.api.java.en.Given;

import Cucumber.api.java.en.Then;

import Cucumber.api.java.en.When;



public
class WeatherTestByZipCode {





@Given("^I have a list of zipcode$")

public
void i_have_a_list_of_zipcode() throws Throwable {


// Write code here that turns the phrase above into concrete actions


throw
new PendingException();

}



@When("^I use the weather service to get the weather information$")

public
void i_use_the_weather_service_to_get_the_weather_information() throwsThrowable {


// Write code here that turns the phrase above into concrete actions


throw
new PendingException();

}



@Then("^the information should be found successfully$")

public
void the_information_should_be_found_successfully() throws Throwable {


// Write code here that turns the phrase above into concrete actions


throw
new PendingException();

}


 

 

Implement the Test Steps Based on Selenium

 Fetch a list of zip codes from a website by Selenium

Then start to implement these missing steps with Selenium. The following code will find the city and zip codes on http://www.phaster.com/zip_code.html and store the parsed valued in a hashtable.

 Call the SoapUITestCaseRunner in JUnit

Following code will use to call the SoapUI test case and set the properties.
Note: “usePropertyFileFlag=false”, which means instead of using a static property file to store the “zipCode” and “city”, we will pass the zipCode and city into the test step at runtime dynamically by setProjectProperties() method.

 

Source Code:

package com.example;
import org.junit.Assert.assertArrayEquals;
import java.util.Hashtable;

import java.util.Iterator;

import java.util.List;

import java.util.Map.Entry;

import java.util.Set;

import java.util.concurrent.TimeUnit;

import org.openqa.Selenium.By;

import org.openqa.Selenium.WebDriver;

import org.openqa.Selenium.WebElement;

import org.openqa.Selenium.firefox.FirefoxDriver;

import com.eviware.SoapUI.tools.SoapUITestCaseRunner;

import Cucumber.api.java.en.Given;

import Cucumber.api.java.en.Then;

import Cucumber.api.java.en.When;

public
class GetWeatherByZipTest {
    private Hashtable<String, String> zipAndCities;

    private
int
failureCount =0, totalCount= 0;

    private StringBuffer zipCodes = new StringBuffer();

    public WebDriver driver;

    

    @Given("^I have a list of zipcode$")

    public
void i_have_a_list_of_zipcode(){


        driver = new FirefoxDriver();

        driver.manage().window().maximize();

        driver.manage().timeouts().implicitlyWait(50, TimeUnit.SECONDS);

        driver.get("http://www.phaster.com/zip_code.html");

        

        List<WebElement> rows =driver.findElements(By.cssSelector("blockquote tr"));

        zipAndCities = new Hashtable<>();

        for (int i = 1; i < 5; i++) {

            List<WebElement> columns = rows.get(i).findElements(By.cssSelector("td"));

            String city = columns.get(1).getText().split("\n")[0].split("\\(")[0];

            String zipCode = columns.get(2).getText().split(" ")[0].split("-")[0].split("\n")[0];

            zipAndCities.put(zipCode, city);

        }

    }

    

    @When("^I use the weather service to get the weather information$")

    public
void i_use_the_weather_service_to_get_the_weather_information() {

        Set<Entry<String, String>> set = zipAndCities.entrySet();

        Iterator<Entry<String, String>> iterator = set.iterator();

        while (iterator.hasNext()) {

            Entry<String, String> entry = iterator.next();

            String zipCode = entry.getKey();

            String city = entry.getValue();

            String[] prop ={"usePropertyFileFlag=true","zipCode="+zipCode,"city="+city};

            

            try {

                SoapUITestCaseRunner SoapUITestCaseRunner= newSoapUITestCaseRunner();

             SoapUITestCaseRunner.setProjectFile("src/test/resources/WeatherSoapTest-SoapUI-project.xml");

                SoapUITestCaseRunner.setProjectProperties(prop);

                SoapUITestCaseRunner.setTestSuite("TestSuite 1");

                SoapUITestCaseRunner.setTestCase("TestCase 1");

                SoapUITestCaseRunner.run();

            } catch (Exception e) {

                System.err.println("checking " + zipCode + " failed!");

                failureCount++;

                zipCodes.append(zipCode + " [" + city +"] ");

                e.printStackTrace();

            }finally{

                totalCount++;

            }

        }

    

    }

    

    @Then("^the information should be found successfully$")

    public
void the_information_should_be_found_successfully() {

        assertArrayEquals("There are " + failureCount +" in " +totalCount+" cities are not found, " + zipCodes.toString(), new
int[]{0}, new
int[]{failureCount});

        driver.quit();

    }



}

 

You could run the test from maven command line as well

1

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s