You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Cucumber测试中通过运行时导入WSDL实现动态SOAP客户端?

我懂你要的是什么——不想提前用wsimport生成一堆静态代码,而是在Cucumber测试运行时,直接拉取远程服务器的WSDL,动态生成SOAP客户端对吧?这完全可以实现,下面给你两种实用方案,都是Java生态下的,完美适配Cucumber的测试场景:

方案1:使用JAX-WS原生动态客户端(无需额外依赖)

JDK自带的JAX-WS API就支持动态解析WSDL,不需要引入第三方库,核心是用Service和Dispatch类来实现。

方式A:基于Dispatch的完全动态调用(无需预定义接口)

这种方式不需要任何提前生成的代码,直接构建SOAP请求并解析响应,灵活性拉满:

import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import javax.xml.namespace.QName;
import java.net.URL;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;

public class SoapDynamicClient {
    public Dispatch<Element> createDispatch(String wsdlUrl, String serviceNs, String serviceName, String portName) throws Exception {
        URL wsdlLocation = new URL(wsdlUrl);
        // 从WSDL中获取服务的QName(命名空间+服务名)
        QName serviceQName = new QName(serviceNs, serviceName);
        Service service = Service.create(wsdlLocation, serviceQName);
        
        // 获取端口的QName
        QName portQName = new QName(serviceNs, portName);
        // 创建处理Payload的Dispatch实例
        Dispatch<Element> dispatch = service.createDispatch(portQName, Element.class, Service.Mode.PAYLOAD);
        
        // 可选:设置SOAP版本(比如SOAP 1.1)
        ((SOAPBinding) dispatch.getBinding()).setSOAPVersion(SOAPBinding.SOAP11HTTP_BINDING);
        return dispatch;
    }
}

在Cucumber步骤中调用的示例:

import io.cucumber.java.en.Given;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.CoreMatchers.equalTo;

public class SoapTestSteps {
    private Dispatch<Element> dispatch;

    @Given("初始化SOAP动态客户端,WSDL地址为{string}")
    public void initClient(String wsdlUrl) throws Exception {
        SoapDynamicClient clientHelper = new SoapDynamicClient();
        dispatch = clientHelper.createDispatch(
            wsdlUrl,
            "http://your-service-namespace.com/", // 从WSDL的targetNamespace获取
            "YourServiceName", // WSDL中<service>标签的name属性
            "YourServicePort" // WSDL中<port>标签的name属性
        );
    }

    @Given("调用服务的{string}方法,参数为{string}")
    public void callServiceMethod(String methodName, String paramValue) throws Exception {
        // 手动构建SOAP请求的Payload
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        Document doc = dbf.newDocumentBuilder().newDocument();
        Element methodElement = doc.createElementNS("http://your-service-namespace.com/", methodName);
        Element paramElement = doc.createElement("paramName"); // 对应WSDL中的参数名
        paramElement.setTextContent(paramValue);
        methodElement.appendChild(paramElement);

        // 发送请求并获取响应
        Element response = dispatch.invoke(methodElement);
        
        // 断言响应结果
        assertThat(response.getTextContent(), equalTo("预期返回值"));
    }
}
方案2:使用Apache CXF动态客户端(更简洁,推荐)

如果觉得手动构建DOM太麻烦,Apache CXF提供了更易用的动态客户端API,能自动解析WSDL并生成动态代理,直接通过方法名调用服务。

第一步:添加CXF依赖(Maven为例)

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxws</artifactId>
    <version>3.6.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http</artifactId>
    <version>3.6.2</version>
    <scope>test</scope>
</dependency>

第二步:编写动态客户端工具类

import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.endpoint.Client;

public class CxfDynamicClient {
    public Client createClient(String wsdlUrl) throws Exception {
        JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance();
        // 直接加载WSDL生成客户端
        return factory.createClient(wsdlUrl);
    }
}

在Cucumber步骤中使用

import io.cucumber.java.en.Given;
import io.cucumber.java.Before;
import org.apache.cxf.endpoint.Client;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.CoreMatchers.equalTo;

public class CxfSoapTestSteps {
    private Client cxfClient;

    // 提前初始化客户端,避免每次步骤重复加载WSDL
    @Before
    public void setUp() throws Exception {
        CxfDynamicClient clientHelper = new CxfDynamicClient();
        cxfClient = clientHelper.createClient("http://remote-server/your-service?wsdl");
    }

    @Given("调用CXF动态客户端的{string}方法,参数为{string}")
    public void callCxfService(String methodName, String param) throws Exception {
        // 直接通过方法名调用,参数按顺序传入
        Object[] responses = cxfClient.invoke(methodName, param);
        
        // 处理响应结果(responses数组对应方法的返回值/输出参数)
        assertThat(responses[0], equalTo("预期返回值"));
    }
}
额外注意事项
  • 认证处理:如果WSDL或服务需要Basic Auth,CXF可以添加拦截器:
    cxfClient.getOutInterceptors().add(new org.apache.cxf.interceptor.security.AuthenticationInterceptor("username", "password"));
    
    JAX-WS原生Dispatch可以通过BindingProvider设置:
    BindingProvider bp = (BindingProvider) dispatch;
    Map<String, Object> context = bp.getRequestContext();
    context.put(BindingProvider.USERNAME_PROPERTY, "username");
    context.put(BindingProvider.PASSWORD_PROPERTY, "password");
    
  • 性能优化:在Cucumber的@Before钩子中初始化客户端,复用实例,避免每次步骤都重新加载WSDL。

内容的提问来源于stack exchange,提问作者user35253

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:00:02