DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Software Design and Architecture
  3. Integration
  4. How to stub SOAP in PHP

How to stub SOAP in PHP

Giorgio Sironi user avatar by
Giorgio Sironi
·
Apr. 28, 13 · Interview
Like (0)
Save
Tweet
Share
9.63K Views

Join the DZone community and get the full member experience.

Join For Free

I do not usually dismiss technologies without regarding to context, but if you have modern web applicatons in mind SOAP is simply wrong, starting from its name: Simple Object Access Protocol. One of the principles of OOP (and distributed computing) is to provide as few different integration points as possible, not to provide a simple way to access private objects  of an application while trying to abstract away the programming language!

How wonderful is the world of REST (or maybe ROT) web services... But many legacy and enterprise systems that we need to integrate are only accessible via SOAP. With a bit of experience and the right testing support, SOAP web services are not technologically difficult to call from PHP code.

Testing at the unit level

To test your adapter object, you need to isolate it from the real TCP/IP stack. In order to accomplish this, it is useful to introduce one of these two abstractions:

interface SoapChannel
{
   /**
    * @return SoapClient
    */
   public function newClient($wsdl, $options = array());
} 

Since PHP code access SOAP services through the native SoapClient object, we need to substitute it with a Stub inside the context of your test suite. However, code that needs to access several different services for the integration will need to specify multiple times a wsdl or some location options: for this reason the newClient() method accept this configuration and return a SoapClient.

In the production environment, newClient() returns a real SoapClient object created with the passed parameters; in testing, it can return your own Stub or one generated by PHPUnit's getMockFromWsdl() utility method.

The other option, when the integration code is calling only one or a few different services, is to provide an Endpoint abstraction:

interface SoapEndpoint
{
   /**
    * @return array
    */
   public function call($function, array $parameters);
} 

The interface is the ultimate layer called by your code, so it's a generic abstraction employed by the Facades you introduce over external services. Let me rephrase: only one object in your code should call each different concrete SoapEndpoint, so that dependencies are shaped like:

[VodafoneFacade] -> [SoapEndpoint]
[MyObject] -> [VodafoneFacade]
[AnotherObject] -> [VodafoneFacade]

Each implementation creates its own SoapClient, hiding away details such as the WSDL file and the location of the service. This design choice reduces the extrinsic coupling (how many collaborators you have) of integration objects from:

public function __construct(SoapChannel $channel, $location) {
   $this->channel = $channel;
   $this->wsdl = ...;
   $this->options = array('location' => $location);
} 

to

public function __construct(SoapEndpoint $endpoint)
{
   $this->endpoint = $endpoint;
}

The word endpoint may sometimes cause REST developers to snicker, I agree. Also, the SoapChannel abstraction is usually much less invasive to introduce in legacy code that calculates its own configuration parameters and creates new SoapClient objects whenever needed. I advise you to introduce directly SoapEndpoint on new code.

I also advise you not to pass around SoapClient objects directly, because an interface such as SoapEndpoint has very little cost (a few lines of code) and a great potential for expansion. For example, you could introduce logging of all external requests with a Decorator object around it.

Testing at the end-to-end level

When you're testing the system at the end-to-end level, I do not advise to Stub part of your code if possible: it causes some of your integration code to never be executed inside the test suite.

What you can do instead is to create external simulators that (out of process) substitute the real web service.

On the client side, you can substitute the location option:

new SoapClient($wsdl, array('location' => 'http://localhost/simulators/vodafone.php')); 

On the server side, you can easily build a SoapServer object:

class Service
{
   public function functionName($params)
   {
     return new \stdClass;
   }
}
$server = new SoapServer($wsdl);
$server->setServiceClass('Service');
$server->handle();

The functionName is the name of the function called on SoapClient in the separate process, while the implementation uses stdClass objects as input (function parameter) and output (returned value).

By creating simulators for external service in this way, you'll be able to reach full coverage of your production code and even to reproduce production integration behavior on your machine.

SOAP Web Protocols PHP Stub (distributed computing)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Detecting Network Anomalies Using Apache Spark
  • NoSQL vs SQL: What, Where, and How
  • The Power of Docker Images: A Comprehensive Guide to Building From Scratch
  • How Chat GPT-3 Changed the Life of Young DevOps Engineers

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: