How to test SOAP Web Services
jakarta.xml.ws services programmatically using JUnit 5 and Apache CXF, as well as with industry-standard tools like SoapUI, JMeter, and cURL. Learn how to configure timeouts, secure connections via TLS, and manage complex routing behind cloud proxies.
This tutorial will teach how to test SOAP Web Services using open source testing tools or Java testing frameworks on modern Jakarta EE runtime environments.
SOAP vs REST: Choosing the Right Integration Path
While RESTful APIs utilizing JSON are widespread for modern mobile and lightweight web services, SOAP (Simple Object Access Protocol) remains a vital standard in enterprise environments. SOAP is uniquely suited for systems requiring strict interface contracts (via WSDL), built-in security profiles (WS-Security), and distributed transactions (WS-AtomicTransaction). Understanding how to efficiently test, debug, and secure SOAP endpoints remains an essential skill for enterprise Java developers.
Coding our SOAP Web Service
Let’s start by defining our Jakarta XML Web Services (JAX-WS) contract using the modern jakarta.* namespace:
package com.mastertheboss.jaxws;
import jakarta.jws.WebMethod;
import jakarta.jws.WebParam;
import jakarta.jws.WebResult;
import jakarta.jws.WebService;
@WebService
public interface AccountWSItf {
@WebMethod
public String newAccount(@WebParam(name = "name") String name);
@WebMethod
public String withdraw(@WebParam(name = "name") String name, @WebParam(name = "amount") long amount) throws RuntimeException;
@WebMethod
public String deposit(@WebParam(name = "name") String name, @WebParam(name = "amount") long amount);
@WebMethod
@WebResult(name = "BankAccount")
public Account findAccountByName(@WebParam(name = "name") String name);
}
This is the SOAP Web Service implementation class leveraging CDI injection and JAX-WS annotations, configured to run on WildFly 41:
package com.mastertheboss.jaxws;
import jakarta.inject.Inject;
import jakarta.jws.WebParam;
import jakarta.jws.WebResult;
import jakarta.jws.WebService;
import jakarta.jws.soap.SOAPBinding;
@WebService(endpointInterface = "com.mastertheboss.jaxws.AccountWSItf", serviceName = "AccountWSService")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class AccountWS implements AccountWSItf {
@Inject
AccountManager ejb;
@Override
public String newAccount(@WebParam(name = "name") String name) {
ejb.createAccount(name);
return "Created Account " + name;
}
@Override
public String withdraw(@WebParam(name = "name") String name,
@WebParam(name = "amount") long amount) throws RuntimeException {
ejb.withdraw(name, amount);
return "withdrawn " + amount;
}
@Override
public String deposit(@WebParam(name = "name") String name,
@WebParam(name = "amount") long amount) {
ejb.deposit(name, amount);
return "deposited " + amount;
}
@Override
@WebResult(name = "BankAccount")
public Account findAccountByName(@WebParam(name = "name") String name) {
return ejb.findAccount(name);
}
}
SOAP Web Service Testing with SoapUI
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 graphical 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 SOAP 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. SoapUI 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, submit the request to 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 extremely handy lightweight option. When testing APIs, always ensure you route requests over HTTPS in production to protect sensitive data payloads. It’s a good idea to have the SOAP XML message generated by SoapUI saved to a file, such as "soap.xml". Then you can run cURL to perform the test:
curl --insecure --header "Content-Type: text/xml;charset=UTF-8" --data @soap.xml https://localhost:8443/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, specifying the service details:
- The NAMESPACE (e.g. “http://ws.jaxws.mastertheboss.com/”)
- The OPERATION name
- The list of ARGUMENTS (if any)
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sam="http://ws.jaxws.mastertheboss.com/">
<soapenv:Header/>
<soapenv:Body>
<sam:newAccount>
<arg0>AAA</arg0>
</sam:newAccount>
</soapenv:Body>
</soapenv:Envelope>
SOAP Web Service Testing with JMeter
If you need to perform performance testing or stress test your web services, you can use Apache JMeter to construct a SOAP Web Service 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 the “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 header. For modern SOAP 1.1 setups, this can be specified or kept empty if already detailed in the payload context:

Finally, configure the Thread Group to simulate the desired concurrent users, ramp-up time, and loop counts, then execute the Test Plan to inspect the results within the Listener interfaces.
Testing your SOAP Web Service Programmatically
In modern Java EE environments like WildFly 41, programmatic testing is implemented using JUnit 5. We will look at two main programmatic clients:
- Using the standard JAX-WS jakarta.xml.ws.Service API to dynamically create a client proxy.
- Using the native JaxWsProxyFactoryBean from Apache CXF (the default web services stack on WildFly 41). This allows you to leverage CXF interceptors and fine-tune connection features.
Differences: JAX-WS Handlers vs. CXF Interceptors
When customizing client requests (logging, WS-Security, header injection), you should understand the distinction between Handlers and Interceptors:
- JAX-WS Handlers: Defined by the Jakarta EE specification, making them portable across application servers (WildFly, Open Liberty, WebSphere). They process logical messages or raw SOAP structures.
- Apache CXF Interceptors: Unique to Apache CXF. They are structured in chain phases (e.g.,
RECEIVE,PRE_STREAM,WRITE) and are much more powerful, as they can access raw streams before the XML model is fully processed, resulting in superior performance.
Automated Java Test Case (JUnit 5)
Below is a modern automated test utilizing standard JAX-WS capabilities, including timeout configuration, and native Apache CXF implementations:
package com.mastertheboss.jaxws.test;
import com.mastertheboss.jaxws.Account;
import com.mastertheboss.jaxws.AccountWSItf;
import jakarta.xml.ws.Service;
import jakarta.xml.ws.BindingProvider;
import javax.xml.namespace.QName;
import java.net.URL;
import java.util.Map;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.ext.logging.LoggingInInterceptor;
import org.apache.cxf.ext.logging.LoggingOutInterceptor;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestWS {
@Test
public void testStandardJAXWSClient() {
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);
// Configuring connection timeouts using Jakarta standard properties
Map<String, Object> requestContext = ((BindingProvider) ws).getRequestContext();
requestContext.put("jakarta.xml.ws.client.connectionTimeout", 5000); // 5s connection timeout
requestContext.put("jakarta.xml.ws.client.receiveTimeout", 10000); // 10s receive timeout
ws.newAccount(name);
System.out.println("Created account name " + name);
ws.deposit(name, 1000);
ws.withdraw(name, 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) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Test
public void testApacheCXFClient() {
String name = "Adam Smith";
System.out.println("TEST Using Apache CXF native API and Interceptors");
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(AccountWSItf.class);
factory.setAddress("http://localhost:8080/ee-ws-basic/AccountWS");
// Modern CXF logging interceptors
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);
ws.withdraw(name, 500);
Account account = ws.findAccountByName(name);
assertNotNull(account);
long money = account.getAmount();
assertEquals(500L, money);
System.out.println("Account balance is " + account.getAmount());
}
}
Deploying to Cloud Environments (Kubernetes & OpenShift)
When running WildFly 41 containers within cloud environments behind reverse proxies or ingress controllers (e.g., NGINX Ingress, Traefik, HAProxy) which terminate SSL, the dynamic WSDL generated by CXF might mistakenly contain internal HTTP links instead of the external HTTPS host names. To resolve this, configure the webservices subsystem using WildFly CLI commands:
/subsystem=webservices:write-attribute(name=wsdl-host, value="api.mastertheboss.com")
/subsystem=webservices:write-attribute(name=wsdl-secure-port, value=443)
/subsystem=webservices:write-attribute(name=wsdl-uri-scheme, value="https")
reload
You can check the full source code of these examples here: https://github.com/fmarchioni/mastertheboss/tree/master/jax-ws/ee-ws-basic
Frequently Asked Questions (FAQs)
Q1: Why do I get a ClassNotFoundException/NoClassDefFoundError with javax.xml.ws.Service in WildFly 41?
A: WildFly 41 implements Jakarta EE 11, which uses the jakarta.* namespace. You must replace all imports of javax.xml.ws.*, javax.jws.*, and javax.xml.bind.* with their jakarta.* equivalents in your code and dependency trees.
Q2: How should client timeouts be configured within the modern JAX-WS API?
A: Timeout configuration can be managed dynamically by casting your web service client port to jakarta.xml.ws.BindingProvider, and modifying the request context map using the standard properties jakarta.xml.ws.client.connectionTimeout and jakarta.xml.ws.client.receiveTimeout.
Q3: How do I handle authentication securely when testing SOAP APIs?
A: Never use plain-text Basic Authentication over unencrypted HTTP. Always ensure the endpoint is exposed over HTTPS (TLS) and configure WS-Security policies or standard HTTPS client-side certificates if transport or message-level encryption is required.
Recommended Articles
Developing SOAP Web Services on WildFly 41 (Jakarta EE 11) with Apache CXF
Learn how to develop, deploy, and secure Jakarta XML Web Services (SOAP) on WildFly 41.0.1.Final and Jakarta EE 11 using Apache CXF, WS-Security, and modern testing tools.
Deploying SOAP Web Services in Jakarta EE Applications: A Step-by-Step Guide
Learn how to build and deploy SOAP-based web services in Jakarta EE applications, including guidance on the changes in Java SE that removed the JAX-WS API.
How to develop CXF Web services with JBoss / WildFly
Learn how to develop, deploy, and secure SOAP Web Services on WildFly 41.0.1.Final using Jakarta EE 11 and Apache CXF. Master JAX-WS handlers, CXF interceptors, and robust cloud configurations.
Creating SOAP Messages Programmatically with Jakarta EE 11 and WildFly 41
Master programmatic SOAP message creation and parsing using SAAJ (Jakarta SOAP with Attachments 3.0) on WildFly 41.0.1.Final and Jakarta EE 11. Complete code examples included.