DEV Community

Cover image for Stop Waiting for the SOAP Test Environment
Ankit Jain
Ankit Jain

Posted on

Stop Waiting for the SOAP Test Environment

A shared ERP test environment is a poor place to discover that your client treats an unknown SKU as zero stock.

Consider a hypothetical customer portal that calls an inventory service through SOAP. A quantity of zero means the item exists but has no available stock. An unknown SKU means the lookup failed. If the adapter collapses both outcomes into “unavailable,” the portal hides a catalog problem behind an ordinary stock message.

I want that distinction in CI before the team books an integration window. Service virtualization gives the real SOAP client a repeatable dependency, so developers can exercise response handling whenever they change the adapter.

Start from the binding

Take one operation from the provider's WSDL and the schemas it references. Record the selected service and port, SOAP version, action, request element, response element, and declared fault detail. Pin the contract revision alongside the fixtures.

For this example, we choose SOAP 1.1 over HTTP, a document/literal binding, and a GetStock operation. The application namespace is urn:example:inventory:v1. The following request uses synthetic data:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
            xmlns:inv="urn:example:inventory:v1">
  <s:Body>
    <inv:GetStock><inv:Sku>TEST-001</inv:Sku></inv:GetStock>
  </s:Body>
</s:Envelope>
Enter fullscreen mode Exit fullscreen mode

Our binding specifies Content-Type: text/xml; charset="utf-8" and SOAPAction: "urn:inventory:GetStock". Those values belong to this example. Read the actual binding instead of deriving the action from the operation's spelling. The SOAP 1.1 HTTP specification describes the SOAPAction header and XML transport. SOAP 1.1 HTTP binding

Keep version differences explicit. SOAP 1.2 uses a different envelope namespace, and its HTTP binding supports application/soap+xml with an optional action parameter. Changing a content-type header alone does not convert a SOAP 1.1 exchange into SOAP 1.2. SOAP 1.2 HTTP binding

Keep your application's actual SOAP client in the test path. Override its destination through configuration. Zeep, for example, documents creating a service proxy with a selected binding and replacement address. Whatever client you use, verify that the outgoing request reaches the virtual endpoint rather than the address embedded in the WSDL. Zeep service configuration

Build the virtual service

Beeceptor supports importing WSDL 1.1 and creating mocks for SOAP 1.1 and 1.2. It exposes parsed operations and lets you customize generated response payloads. Start with this example's self-contained WSDL, inspect the generated envelopes, and set the stock values and fault details your tests need. That gives the team a repeatable inventory service with fixtures they can review alongside the application code. SOAP server from WSDL

The portal keeps its real SOAP client and calls a Beeceptor virtual inventory service. CI exercises valid responses, SOAP faults, and invalid XML contracts; a separate check targets the real ERP.

For POST /soap, configure a rule that matches the example's action and returns a deterministic success envelope with Quantity equal to 7. Add separate fixtures for zero stock and the declared unknown-SKU fault.

Beeceptor's SOAPAction Matches filter identifies an operation from request components including the HTTP header and SOAP body. Use it to route GetStock calls to the intended fixture, then inspect the captured request to assert the action and binding specified in your contract. SOAP operation matching

Select one response fixture per isolated test endpoint, or put narrow scenario rules above the ordinary success rule. Beeceptor uses the first matching rule in top-to-bottom order. Avoid concurrent tests that overwrite a shared endpoint's active fixture. Rule execution order

Make namespaces count

An XML prefix is an alias. An element's expanded name combines its namespace URI and local name. A response using stock:GetStockResponse can represent the same element as inv:GetStockResponse when both prefixes refer to urn:example:inventory:v1. Keeping the prefix while changing that URI changes the element's identity. Namespaces in XML

Test both cases. A namespace-aware client should accept a renamed prefix for the same contract. Your integration should surface a response from an unexpected namespace as a contract error, either through the client or an explicit validation layer.

Beeceptor provides a simplified parsed XML representation for response templates. Use it to read request values when creating dynamic responses. In the integration suite, check the raw XML with namespace-aware assertions and validate the relevant body element against your pinned XSD. These checks exercise the client against the precise contract your application expects. SOAP envelope templating

The fault fixture needs equal care. Under the SOAP 1.1 HTTP binding, a SOAP processing error returns HTTP 500 with a SOAP Fault. Preserve that body so the SOAP stack can decode it; a generic HTTP error handler can otherwise discard the detail the adapter needs. SOAP 1.1 fault response

Here is our hypothetical unknown-SKU fault. Its application detail comes from the example contract:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
            xmlns:inv="urn:example:inventory:v1">
  <s:Body>
    <s:Fault>
      <faultcode>s:Client</faultcode>
      <faultstring>Unknown SKU</faultstring>
      <detail><inv:StockFault><inv:Code>SKU_UNKNOWN</inv:Code></inv:StockFault></detail>
    </s:Fault>
  </s:Body>
</s:Envelope>
Enter fullscreen mode Exit fullscreen mode

Map SKU_UNKNOWN to an explicit catalog lookup error. Do not infer retry eligibility from HTTP 500 alone, and do not turn the fault into an empty success response. A 500 containing an HTML gateway error needs a separate integration-error path.

The core assertions fit in a small suite:

Fixture Required application outcome
Valid response, quantity 7 Return seven available units
Valid response, quantity 0 Return a valid zero-stock result
Different prefix, same namespace Preserve the valid result
Wrong namespace or missing required quantity Surface a contract error
HTTP 500 with SKU_UNKNOWN fault detail Surface the catalog lookup error
HTTP 500 with HTML instead of a SOAP Fault Surface an integration error

Confirm the provider

Virtualization lets you exercise those outcomes on every relevant build. Keep a smaller provider suite for the real endpoint, credentials, certificates, and any required message-security policy. An XML fixture cannot establish that the deployed ERP accepts your signed request or authorizes your service account.

Compare the generated client's actual request with the pinned contract. Check the selected binding, action, body QName, and required headers. When the provider changes, review the fixtures alongside the client and application behavior.

With a reproducible SOAP boundary, your team can verify the difficult client behaviors before the next integration window opens. Make every build a step toward a legacy integration your team can confidently release.

Top comments (0)