【问题标题】:Phpunit - mocking SoapFault->getMessage()Phpunit - 模拟 SoapFault->getMessage()
【发布时间】:2011-11-24 11:58:38
【问题描述】:

我正在使用 SOAP 连接到 third party service。此服务有时会返回 SoapFaults。因为这是预期的,所以我想通过模拟 SoapFaults 来测试它。它会返回五个标准的 SoapFaults。

这是真正的 SoapFault 的开始:

object(SoapFault)#7 (11) {
  ["message":protected]=>
  string(19) "{ 'INVALID_INPUT' }"

我对此消息感兴趣。在我的代码中,我使用 $e->getMessage()。

catch (SoapFault $e)
{
    // Catch any Soap faults and convert to an error message
    switch ($e->getMessage())
    {
        case "{ 'INVALID_INPUT' }":
            $this->addError(self::INVALID_INPUT);
            return FALSE;

但我不知道如何模拟 SoapClient 响应。 SoapClient 对象似乎没有接受任何输入来设置消息,并且方法getMessage() 是最终的,所以我无法模拟它。

任何想法将不胜感激。谢谢。

【问题讨论】:

  • 如果有帮助:new SoapFault(0, 'put your message here'); 将设置 getMessage(); 返回值。

标签: php soap phpunit


【解决方案1】:

应该没有必要模拟SoapFault。您可以只使用真正的异常(通常不会模拟异常以进行测试,因为它们是 Value objects)并模拟 SoapClient 以抛出您准备好的异常。

通过这样做,您可以避免无法模拟 getMessage,因为您在测试用例中构建了 SoapFault,如下所示。

由于我一直在弄清楚您的问题到底是什么,所以我构建了一个小测试用例以确保它可以解决。因为它已经在那里了,所以我猜代码解释得比我能解释得更好。

测试示例:

<?php

class SoapFaultTest extends PHPUnit_Framework_TestCase {

    public function testSoapFault() {
        $soapFault = new SoapFault("test", "myMessage");
        $soapClient = $this->getMockBuilder('SoapClient')
            ->setMethods(array('methodOnService'))
            ->disableOriginalConstructor()
            ->getMock();

        $soapClient->expects($this->once())
            ->method('methodOnService')
            ->will($this->throwException($soapFault));

        $x = new Consumer();
        $this->assertSame(
            "InvalidInput",
            $x->doSoapStuff($soapClient)
        );  
    }   

}

class Consumer {

    public function doSoapStuff(SoapClient $soapClient) {
        try {
            $soapClient->methodOnService();
        } catch(Exception $e) {
            if($e->getMessage() == "myMessage") {
                return "InvalidInput";
            }   
        }   
    }   
}

输出:

 phpunit SoapFaultTest.php 
PHPUnit 3.6.3 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 3.75Mb

OK (1 test, 2 assertions)

断言保持简单,但您应该能够轻松地将其调整为您处理错误的方式

【讨论】:

    【解决方案2】:

    除了 edorian 的回答之外,应该没有必要测试第三方组件是否按宣布的那样工作。不要为您没有编写代码的组件编写测试(或者您无法编写代码的组件,如果它们被破坏,它们就会被破坏并且您会迷路)。

    只需测试您的代码是否按预期工作。您应该能够模拟自己的代码。

    示例:如果缺少代码或数据,您的代码将始终中断,例如在某些情况下,您的应用程序文件会被部分删除。您是否为此类场景编写测试?自然不会。

    但是,您可以为自己编写一个集成套件,该套件会自动测试某些远程依赖项是否提供了预期的接口和响应。但我会将那个套件与涵盖您自己的代码库的测试套件分开。

    此外,您可以在每个测试用例中使用create your own assertion functions,例如一个用于 SoapClient 异常消息。

    【讨论】:

    • 我只是希望他能模拟出 SoapClient 调用(因为再次测试远程服务然后模拟一个故障对我来说会很奇怪),但你需要解耦。我只是假设他正在测试的只是他的代码处理了另一边的错误,并且需要帮助生成用于测试的错误:)
    • @edorian:你是对的,阅读你的答案实际上建议不要测试远程组件,而只测试自己的代码如何对来自远程访问层的可能输入值做出反应。
    【解决方案3】:

    我要感谢 hakre 的评论。这正是我想要的。

    SoapFault 扩展了 Exception,它需要 ($message, $code, $previous) 的输入。 但是 SoapFault 期望 ($faultcode, $faultstring, $faultactor, $detail, $faultname, $headerfault)。 这就是让我震惊的原因。

    $faultstring 映射到异常消息。

    为了模拟它,我做了:

    $mock_soap->expects($this->once())
                             ->method('checkVat')
                             ->will($this->throwException(new SoapFault('a', "Error Message")));
    

    在我的真实代码中 $e->getMessage() 现在返回“错误消息”

    【讨论】:

      猜你喜欢
      • 2016-06-13
      • 1970-01-01
      • 1970-01-01
      • 2020-10-25
      • 2014-11-07
      • 2015-11-01
      • 2017-01-13
      • 1970-01-01
      • 2018-11-10
      相关资源
      最近更新 更多