How to test SOAP Web Services

This tutorial will teach how to test SOAP Web Services using open source testing tools or Java testing frameworks.

Coding our SOAP Web Service

Let’s start from the definition of our JAX-WS Web Service contract:

@WebService
public interface AccountWSItf {
	@WebMethod
	public String newAccount( String name);

	@WebMethod
	public String withdraw(String name, long amount) throws RuntimeException;

	@WebMethod
	public String deposit(String name, long amount);

	@WebMethod
	public Account findAccountByName(String name);
}

This is the SOAP Web Service implementation:

@WebService
@SOAPBinding(style= SOAPBinding.Style.RPC)
public class AccountWS implements AccountWSItf{
	@Inject
	AccountManager ejb;

 
	public String newAccount(@WebParam(name = "name") String name) {
		ejb.createAccount(name);
        return "Created Account "+name;
	}

 
	public String withdraw(@WebParam(name = "name") String name,
			@WebParam(name = "amount") long amount) throws RuntimeException {
		ejb.withdraw(name, amount);
		return "withdrawn "+amount;
	}

 
	public String deposit(@WebParam(name = "name") String name,
			@WebParam(name = "amount") long amount) {
		ejb.deposit(name, amount);
		return "deposited "+amount;
	}

	@WebResult(name = "BankAccount")
	public Account findAccountByName(String name) {
		return ejb.findAccount(name);
	}
}

SOAP Web Service Testing with SOAP UI

In order to test a Web Service we need to collect the WSDL URL of the Web service. This tutorial discusses how you can get the URL of a SOAP Web Service on WildFly: How do I know the WSDL URL of my Web Service ?

The recommended option for Web Service Testing is SOAPUI which is available in an OpenSource version and in an Enterprise version called ReadyAPI. You can download SOAPUI from: https://www.soapui.org/downloads/soapui/

Once installed, it’s really simple to perform Web Service testing: select the New Project option from the File menu, which will prompt the following dialog:

Enter the project name and the WSDL address of your SOAP Web service. SOAP UI will import the WSDL and generate a default request for ad-hoc testing and exploring of services:

So for example, to test the “newAccount” action you only have to add the arguments in the SOAP payload:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.jaxws.mastertheboss.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <ws:newAccount>
         <!--Optional:-->
         <arg0>JohnSmith</arg0>
      </ws:newAccount>
   </soapenv:Body>
</soapenv:Envelope>

Then, you can check the Web Service response:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns2:newAccountResponse xmlns:ns2="http://ws.jaxws.mastertheboss.com/">
         <return>Created Account JohnSmith</return>
      </ns2:newAccountResponse>
   </soap:Body>
</soap:Envelope>

SOAP Web Service Testing with cURL

If you want to test your Web Services in a pure and simple bash script, cURL is an handy option. It’s a good idea to have the SOAP XML message generated by SOAPUI, so for example if you saved the above SOAP XML request in a file named “soap.xml”, then you can test the Web Service with cURL as follows:

curl  --header "Content-Type: text/xml;charset=UTF-8"  --data @soap.xml http://localhost:8080/ee-ws-basic/AccountWS

On the other hand, if you don’t have a tool to generate the SOAP XML message to be sent, you can start from a basic template like this one, and specify in it;

  • The NAMESPACE (e.g. “sample.com”)
  • The OPERATION name
  • The list of ARGUMENTS (if any)
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sam="http://NAMESPACE/">
   <soapenv:Header/>
   <soapenv:Body>
      <sam:OPERATION>          
         <arg0>AAA</arg0>         
      </sam:OPERATION>
   </soapenv:Body>
</soapenv:Envelope>

SOAP Web Service Testing with JMeter

If you are going to run a stress test for your Web Services, then you can use JMeter to build a SOAP Webservice Test Plan. You can download JMeter from https://jmeter.apache.org/download_jmeter.cgi

Launch JMeter and choose from the menu File → Templates… and select template “Building a SOAP Webservice Test Plan”.

Then, click “Create” button. The following Test plan will be created:

Select the HTTP Request and set the server name/port, the Path and the Body Data as you can see from the following picture:

Finally, select the HTTP Header Manager and set the SOAPAction to blank, as we have already specified it in the Body Data payload:

Finally, the Thread Group tells JMeter the number of users you want to simulate, how often the users should send requests, and the how many requests they should send.

You can now run the Test Plan and check the result in the Listener window to visualize the performance of your test.

Testing your SOAP Web Service Programmatically

Finally, let’s check how to test the SOAP Web Service programmatically. We will execute the test using two different strategies:

  • Use the javax.xml.ws.Service class and leveraging our AccountWSItf endpoint interface. With this we can get an implementation of the interface generated dynamically for us that can be used to send compliant SOAP messages to our service.
  • Use the JaxWsProxyFactoryBean from Apache CXF to access and test the Web Service. This requires to add some extra dependencies to test your Web Services however you can enhance the functionality of a JAX-WS endpoint or client proxy, for example by adding interceptors.
public class TestWS {

	@Test
	public void test() {
		 
		String name ="John Smith";
		try {
			URL url = new URL("http://localhost:8080/ee-ws-basic/AccountWS?wsdl");
			QName qname = new QName("http://ws.jaxws.mastertheboss.com/",
					"AccountWSService");

			Service service = Service.create(url, qname);
			AccountWSItf ws = service.getPort(AccountWSItf.class);
			ws.newAccount(name);
			System.out.println("Created account name " +name);
			ws.deposit(name, 1000);
			System.out.println("Deposit $ 1000 ");
			ws.withdraw(name, 500);
			System.out.println("Withdraw $ 500 ");
			Account account = ws.findAccountByName(name);
			assertNotNull(account);

			long money = account.getAmount();
			assertEquals(500l, money);
			System.out.println("Account balance is " +account.getAmount());


		} catch (Exception e) {
			System.out.println("Exception: "+ e);
		}
	}
	@Test
	public void testApacheCXF() {
		String name ="Adam Smith";
		System.out.println("TEST Using Apache CXF native API");

		JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
		factory.setServiceClass(AccountWSItf.class);
		factory.setAddress("http://localhost:8080/ee-ws-basic/AccountWS?wsdl");
		factory.getInInterceptors().add(new LoggingInInterceptor());
		factory.getOutInterceptors().add(new LoggingOutInterceptor());

		AccountWSItf ws = (AccountWSItf) factory.create(); 
		ws.newAccount(name);
		System.out.println("Created account name " +name);
		ws.deposit(name, 1000);
		System.out.println("Deposit $ 1000 ");
		ws.withdraw(name, 500);
		System.out.println("Withdraw $ 500 ");
		Account account = ws.findAccountByName(name);
		assertNotNull(account);
		long money = account.getAmount();
		assertEquals(500l, money);
		System.out.println("Account amount is " +account.getAmount());

	}
}

You can check the full source code of these examples here: https://github.com/fmarchioni/mastertheboss/tree/master/jax-ws/ee-ws-basic