2013-09-20 6 views
0

В настоящее время я работаю над тестированием класса, который генерирует XML на основе объекта значения, отправляет XML через HTTP и анализирует ответ XML на второй объект значения. Я хотел бы протестировать в этом случае сгенерированный XML-объект и проанализированный объект значения на основе данного XML.Как протестировать класс, который генерирует XML внутри

Класс выглядит:

class MyClient 
{ 
    public function send(RequestValues $request) 
    { 
     $document = $this->generateMessage($request); 
     $response = $this->request($document); 

     return $this->parseResponse($response); 
    } 

    protected function generateMessage(RequestValues $request) 
    { 
     $document = new DomDocument; 
     // Do stuff with $request 

     return $document; 
    } 

    public function request(DomDocument $document) 
    { 
     $client = $this->getHttpClient(); 
     $client->setRawBody($document->saveXml()); 
     // Configure client 

     return $client->send(); 
    } 

    public function parseResponse(Response $response) 
    { 
     $parameters = new ResponseValues; 

     $document = new DomDocument; 
     $document->loadXml($response->getBody()); 

     // Fill in $parameters 
     return $parameters; 
    } 
} 

Я хотел бы проверить две вещи:

  1. Учитывая определенный RequestValues аргумент, сгенерированный XML должен выглядеть $string
  2. Учитывая определенный XML (клиент HTTP будет издеваться), ResponseValues должен быть равен $object

Я сейчас пишу тест на # 1, но я думаю, что могу добиться этого только через обратный вызов. Однако обратный вызов не дает мне весьма полезной информации, когда тест не выполняется. Только это сообщение:

Не удалось утверждать, что объект DOMDocument Object() принят указанным обратным вызовом.

Тест выглядит следующим образом:

public function testRequestContainsValidXml() 
{ 
    $client = $this->getMock('MyClient', array('request')); 

    $message = ''; 
    $client->expects($this->once()) 
      ->method('request') 
      ->with($this->callback(function($object) use ($message) { 
       return 
        ($object instanceof DomDocument) 
       && ($object->saveXml() === $message); 
      })); 

    $request = new DirectoryRequest; 
    $client->send($request); 
} 

Вопрос заключается в том: , как я могу улучшить тест таким образом, что нормальное сравнение строк можно? Я хотел бы получить phpunit, говорящий, что «строка X не равна Y», что значительно облегчает отладку.

PS. Полный код этого класса доступен на GitHub. Естественно, вышеприведенный пример - упрощенная версия. Вот фактический класс: https://github.com/juriansluiman/SlmIdealPayment/blob/master/src/SlmIdealPayment/Client/StandardClient.php#L58

PPS. Если код необходимо изменить, чтобы проверить его, это не проблема. Я бы хотел только сохранить публичный API одинаково (т. Е. Звонок ResponseValues send(RequestValues $request)

+0

В чем же проблема? Разве что сравнение '$ object-> saveXml() === $ message' терпит неудачу? – silkfire

+0

@silkfire * if * сообщение $ правильно, оно не подведет и просто пройдет. Однако нет никакого способа узнать, какая разница между ожидаемой и фактической строкой. Вы не можете отлаживать это каким-либо образом при модульном тестировании, что возможно с помощью, например, '$ this-> assertEquals ($ string1, $ string2)'. Скорее, что модульные тесты помогают мне понять ошибки в моем коде, это большой черный ящик и не очень полезно, если у вас случайно есть ошибка. –

+0

Итак, вопрос (также выделен жирным шрифтом), как я могу улучшить ** тест. Я могу получить его, но проблема в том, чтобы получить значимые сообщения из phpunit, когда он не пройдет. –

ответ

0

Вы, класс MyClient, предположили, что это фасад. Для проверки фасада в контексте UnitTests обычно, прежде всего, необходимо проверить все единицы, которые являются сотрудниками этого фасада

Как вы обычно дразнят коллаборационистов. - и не испытываемое устройство -. Ваша установка тест выглядит не так, как вы насмешливый MyClient блок испытуемый, но не это коллаборационистов

Например:

Вы хотите, чтобы st, если метод MyClient::parseResponse() возвращает ожидаемый объект ResponseValues. Поэтому вы бы издевались над Response, поскольку в этом случае он является сотрудником.

Возможно, вы также захотите высмеять другого соавтора (ResponseValues), однако вы не можете, поскольку это скрытая зависимость, которая не может быть введена (вы можете решить это, введя фабрику в MyClient, которая может контролировать создание таких ResponseValues).

Так много для тестирования MyClient::parseResponse(): вы вводите XML-документ прибора через макет Response и выполняете свои утверждения по возвращаемому значению.

Для случая, если запрос содержит действительный XML (testRequestContainsValidXml()), я не думаю, что это должно быть сделано в этой сложной форме. Похоже, что здесь у вас есть HTTP-клиент, вам нужно только проверить, что он работает, и ему все равно, работает ли он с XML, потому что, если он работает, он также работает с XML. Причина, по которой вы проверяете правильность XML, заключается не в том, что вы хотите протестировать клиента. Поэтому сохраните этот тест из клиентских модулей-тестов.

Утверждение для струнного материала кстати. is:

$this->assertSame($expected, $actual); 

Phpunit покажет вам хороший разницу между строками. Некоторые другие программисты/тестеры также применяли некоторую нормализацию XML, когда сравнивали XML, чтобы diff был более читабельным. Вы можете найти Q & A, как PHP XML how to output nice format и связанные с этим полезные, если ваш XML не имеет проблем с незначительными пробелами.

Надеюсь, я смогу точно определить проблемы, с которыми вы сталкиваетесь, и расширить свое представление о проблеме. Я думаю, что вы пришли к лучшему, подвергая сомнению ваш нынешний макет использования критически, для примеров, которые я даю, я полностью сократил насмешку над предоставлением соавторов, а не делал утверждения. Asswertions делаются только на тестируемом блоке, здесь пример MyClient.

Смежные вопросы