Как макетировать тестирование веб-службы в PHPUnit через несколько тестов? - PullRequest
11 голосов
/ 17 марта 2010

Я пытаюсь протестировать класс интерфейса веб-службы с помощью PHPUnit. По сути, этот класс делает вызовы к объекту SoapClient . Я пытаюсь протестировать этот класс в PHPUnit, используя метод getMockFromWsdl, описанный здесь:

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

Однако, так как я хочу тестировать несколько методов из одного и того же класса, каждый раз, когда я настраиваю объект, мне также нужно настроить фиктивный объект WSDL SoapClient . Это приводит к фатальной ошибке:

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

Как я могу использовать один и тот же фиктивный объект в нескольких тестах без необходимости каждый раз регенерировать его из WSDL? Кажется, это проблема.

-

Когда вас попросили опубликовать некоторый код для просмотра, вот метод установки в TestCase:

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

    $this->client = new Client();

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

    $this->client->setClient($this->SoapClient);
}

Ответы [ 6 ]

4 голосов
/ 11 мая 2011

Это не идеальное решение, но в вашей настройке дайте SOAP-макету "случайное" имя класса, например

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

Это гарантирует, что, по крайней мере, при вызове установки вы не получите эту ошибку.

1 голос
/ 11 апреля 2010

Почему вы создаете макет в setUp (), если нужно получить определение макета класса один раз за выполнение всего тестового файла? Если я правильно помню, он запускается перед каждым тестом, определенным в «этом» тестовом классе ... Попробуйте setUpBeforeClass ()

С http://www.phpunit.de/manual/3.4/en/fixtures.html

Кроме того, методы шаблона setUpBeforeClass () и tearDownAfterClass () вызываются до запуска первого теста класса тестового набора и после запуска последнего теста класса тестового случая, соответственно.

1 голос
/ 17 марта 2010

Для базового использования, что-то вроде этого будет работать. PHPUnit делает немного магии за кулисами. Если вы кешируете фиктивный объект, он не будет повторно объявлен. Просто создайте новую копию из этого кэшированного экземпляра, и все будет хорошо.

<?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
}
?>

В качестве альтернативы, вы, возможно, можете кэшировать имя класса с помощью get_class и затем создать новый экземпляр, а не копию. Я не уверен, сколько "волшебного" PHPUnit делает для инициализации, но это стоит попробовать.

<?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);
}
?>
0 голосов
/ 22 сентября 2013

Один из способов передать объект из теста в тест в PHPUnits - это использовать тестовую зависимость, если создание экземпляра конкретного объекта слишком обременительно / требует много времени:

<?php
/**
* Pass an object from test to test
*/
class WebSericeTest extends PHPUnit_Framework_TestCase
{

    protected function setUp() {
        parent::setUp();
        // I don't know enough about your test cases, and do not know
        // the implications of moving code out of your setup.
    }

    /**
    * First Test which creates the SoapClient mock object.
    */
    public function test1()
    {
        $this->client = new Client();

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

        $this->client->setClient($this->SoapClient);
        $this->markTestIncomplete();
        // To complete this test you could assert that the
        // soap client is set in the client object. Or
        // perform some other test of your choosing.

        return $soapClient;
    }

    /**
    * Second Test depends on web service mock object from the first test.
    * @depends test1
    */
    public function test1( $soapClient )
    {
        // you should now have the soap client returned from the first test.
        return $soapClient;
    }

    /**
    * Third Test depends on web service mock object from the first test.
    * @depends test1
    */
    public function test3( $soapClient )
    {
        // you should now have the soap client returned from the first test.
        return $soapClient;
    }
}
?>
0 голосов
/ 17 сентября 2013

Добавление моих $ .02 здесь .. Я недавно столкнулся с этой же ситуацией, и после некоторого разочарования вот как я смог ее решить:

class MyTest extends PHPUnit_Framework_TestCase
    protected static $_soapMock = null;

    public function testDoWork_WillSucceed( )
    {
        $this->_worker->setClient( self::getSoapClient( $this ) );
        $result = $this->_worker->doWork( );
        $this->assertEquals( true, $result['success'] );
    }

    protected static function getSoapClient( $obj )
    {
        if( !self::$_soapMock ) {
            self::$_soapMock = $obj->getMockFromWsdl( 
                'Test/wsdl.xml', 'SoapClient_MyWorker'
            );
        }

        return self::$_soapMock;
    }
}

У меня есть много «работников», каждый из которых имеет свой собственный класс тестирования, и каждому из которых требуется доступ к макетированному объекту SOAP. Во втором параметре getMockFromWsdl мне нужно было убедиться, что я передаю каждому уникальное имя (например, SoapClient_MyWorker), иначе это приведет к краху PHPUnit.

Я не уверен, является ли получение SOAP-макета из статической функции и получение доступа к функции getMockFromWsdl путем передачи $this в качестве параметра лучшим способом для достижения этой цели, но вы идете.

0 голосов
/ 21 сентября 2010

PHPUnit создает класс для макета на основе WSDL. Имя класса, если оно не указано, создается из имени файла .wsdl, поэтому оно всегда одинаково. Через тесты, когда он пытается снова создать класс, он падает.

Единственное, что вам нужно, это добавить в определение Mock собственное имя класса, чтобы PHPUnit не создавал автоматического имени, обратите внимание на второй аргумент $ this-> getMockFromWsdl:

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

   $this->client = new Client();

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

   $this->client->setClient($this->SoapClient);
}

Теперь вы можете создавать столько клиентов, сколько хотите, только меняйте имя класса для каждого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...