Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock test a web service in PHPUnit across multiple tests?

I am attempting to test a web service interface class using PHPUnit. Basically, this class makes calls to a SoapClient object. I am attempting to test this class in PHPUnit using the getMockFromWsdl method described here:

http://www.phpunit.de/manual/current/en/test-doubles.html#test-doubles.stubbing-and-mocking-web-services

However, since I want to test multiple methods from this same class, every time I setup the object, I also have to setup the mock WSDL SoapClient object. This is causing a fatal error to be thrown:

Fatal error: Cannot redeclare class xxxx in C:\web\php5\PEAR\PHPUnit\Framework\TestCase.php(1227) : eval()'d code on line 15

How can I use the same mock object across multiple tests without having to regenerate it off the WSDL each time? That seems to be the problem.

--

Having been asked to post some code to look at, here's the setup method in the TestCase:

protected function setUp() {
    parent::setUp();

    $this->client = new Client();

    $this->SoapClient = $this->getMockFromWsdl(
        'service.wsdl'
    );

    $this->client->setClient($this->SoapClient);
}
like image 940
scraton Avatar asked Mar 16 '10 21:03

scraton


2 Answers

This isn't an ideal solution, but in your setup give the SOAP mock a "random" class name, for example

$this->_soapClient = $this->getMockFromWsdl( 'some.wsdl', 'SoapClient' . md5( time().rand() ) );

This ensures that at least when the setup is called you don't get that error.

like image 105
James Dunmore Avatar answered Oct 14 '22 22:10

James Dunmore


For basic usage, something like this would work. PHPUnit is doing some magic behind the scenes. If you cache the mock object, it won't be redeclared. Simply create a new copy from this cached instance and you should be good to go.

<?php
protected function setUp() {
    parent::setUp();

    static $soapStub = null; // cache the mock object here (or anywhere else)
    if ($soapStub === null)
        $soapStub = $this->getMockFromWsdl('service.wsdl');

    $this->client = new Client;
    $this->client->setClient(clone $soapStub); // clone creates a new copy
}
?>

Alternatively, you can probably cache the class's name with get_class and then create a new instance, rather than a copy. I'm not sure how much "magic" PHPUnit is doing for initialization, but it's worth a shot.

<?php
protected function setUp() {
    parent::setUp();

    static $soapStubClass = null; // cache the mock object class' name
    if ($soapStubClass === null)
        $soapStubClass = get_class($this->getMockFromWsdl('service.wsdl'));

    $this->client = new Client;
    $this->client->setClient(new $soapStubClass);
}
?>
like image 44
pestilence669 Avatar answered Oct 14 '22 20:10

pestilence669