Part 7: Testing, Performance, and Integration Patterns

Testing SOAP Services

Testing SOAP services is not fundamentally different from testing any other service β€” you need unit tests for your service logic, integration tests that use real SOAP calls, and a way to mock the SOAP layer when testing code that depends on an external SOAP service.

What is different with SOAP is that the XML format creates additional things to verify: are the types correct, does the fault structure match the contract, does the WSDL accurately reflect the service?

This part covers all of these and adds performance and integration patterns for using SOAP in a modern Python architecture.

Unit Testing spyne Services

spyne service methods are plain Python β€” they receive typed arguments and return typed objects. Test them directly without any SOAP or HTTP overhead.

Project Structure for Tests

soap_inventory/
β”œβ”€β”€ models.py
β”œβ”€β”€ service.py
β”œβ”€β”€ faults.py
β”œβ”€β”€ app.py
└── server.py
tests/
β”œβ”€β”€ conftest.py
β”œβ”€β”€ unit/
β”‚   β”œβ”€β”€ test_service.py
β”‚   └── test_faults.py
β”œβ”€β”€ integration/
β”‚   └── test_soap_client.py
└── fixtures/
    β”œβ”€β”€ soap_fault_product_not_found.xml
    └── soap_response_get_product.xml

Unit Tests for Service Methods

Testing the Generated WSDL

Check that the WSDL generated by spyne contains the expected operations:

Integration Testing with a Live zeep Client

Integration tests run against the real SOAP server and verify the full request/response cycle including XML serialisation.

Mocking SOAP Responses in Application Tests

When testing application code that calls a SOAP service, you do not want to hit the real service. Mock the zeep client with pytest-mock or unittest.mock.

Mocking at the Service Method Level

Fixture XML Files for Response Mocking

For complex response structures, store expected XML in fixture files rather than constructing them in code:

Performance Considerations

1. WSDL Loading Cost

WSDL parsing is the biggest startup cost in zeep. On a slow network, loading a large WSDL with multiple imported schemas can take 2–5 seconds.

Mitigation: Singleton client per process

Use get_soap_client(wsdl_url) throughout the application β€” the WSDL and client are loaded once and reused.

2. XML Parsing Overhead

SOAP messages are XML and XML parsing is CPU-intensive compared to JSON. For high-throughput applications, a few guidelines:

  • Avoid re-parsing the WSDL on every request (use the singleton pattern above)

  • Use connection pooling β€” the requests.Session with a requests.adapters.HTTPAdapter and pool_connections / pool_maxsize parameters

  • Compress responses β€” if the service supports Accept-Encoding: gzip, enabling it can reduce payload sizes by 60–80%

3. Async SOAP Clients with httpx

For high-concurrency workloads (e.g., a FastAPI endpoint calling a SOAP service), use httpx as the transport to enable async:

SOAP-to-REST Proxy Pattern

A common integration pattern is exposing a SOAP backend through a REST API. This lets modern frontends and microservices consume SOAP services without knowing about XML.

Observability: Logging and Tracing SOAP Traffic

For production systems, structured logging of SOAP calls is essential for debugging integration issues:

Series Recap

This series covered the full lifecycle of working with SOAP web services in Python:

Part
Topic

SOAP message structure, Envelope/Header/Body/Fault, SOAP 1.1 vs 1.2, raw Python requests

WSDL sections, XSD types, reading WSDLs with zeep, writing minimal WSDL

spyne service definition, ComplexModel, @rpc, Flask hosting, event handlers

zeep client setup, complex types, sessions, WSDL caching, debugging

WS-Security UsernameToken, PasswordDigest, timestamps, X.509 signatures

SOAP Fault structure, typed faults in spyne, fault handling in zeep

Unit/integration testing, mocking, performance, SOAP-to-REST proxy

SOAP is not the future of APIs, but it is a present reality for a large portion of enterprise software. Understanding it deeply makes integration work faster, debugging easier, and the frustration manageable.

Last updated