在 catch 块中设置对象属性时 PHPUnit 测试失败

Posted

技术标签:

【中文标题】在 catch 块中设置对象属性时 PHPUnit 测试失败【英文标题】:PHPUnit test fails when setting object property within catch block 【发布时间】:2012-11-21 08:48:53 【问题描述】:

我正在测试 setSubject 方法,该方法将主题设置为 (空主题),如果它丢失。 如果试图访问未声明的属性,Zend_Mail 会抛出异常(例如,缺少电子邮件主题,最好抛出一些异常)。更多信息:http://framework.zend.com/issues/browse/ZF-11371 这是我需要使用才能成功测试它:

protected function setSubject()

    # catch exception thrown if non existing $this->message object property is accessed
    try
    
      $this->subject = $this->defunctTheContent($this->message->getHeaders(), $this->message->subject);
    
    catch (Zend_Mail_Exception $e)
    
    
    if( ! $this->subject)
      $this->subject = '(empty subject)';

测试

public function testNoSubject()

  $email = new parseEmail(file_get_contents('mail.x'));
  $this->AssertEquals('(empty subject)', $email->subject);

但是,如果我尝试此代码,您会看到 catch 块是空的...

protected function setSubject()

    try
    
      $this->subject = $this->defunctTheContent($this->message->getHeaders(), $this->message->subject);
    
    catch (Zend_Mail_Exception $e)
    
      $this->subject = '(empty subject)';
    

测试失败并显示消息:

有 1 个错误:

1) Email_ParseTest::testNoSubject InvalidArgumentException:主题是必需的

它抱怨 $this->subject 没有设置(或类似的)。

更多信息:

php 5.4.8 Zend 框架 1.9.5 PHPUnit 3.6.12 subject 定义为空字符串 ("")

我已经“手动”测试了第二种方法,它按预期工作(主题设置在 catch 块中)。我对 PHPUnit 没有太多经验,所以这可能很容易成为 E_PEBKAC

【问题讨论】:

你可以试试 var_dump("foo");在 catch 块中查看控制是否进入 catch 块?如果没有,它很可能不会捕获正确的异常。 【参考方案1】:

除非我误解了您的问题,否则您正在尝试测试受保护的方法……您不能这样做。假设通过测试使用它们的公共方法来测试受保护和私有方法。

如果您将 PHP 5.3.2+ 与 PHPUnit 一起使用,则可以通过在运行测试之前使用反射将它们设置为公开来直接测试私有和受保护方法,但是,正如我所提到的,您重新假设测试公共方法。

但是如果你想使用反射,这里有一个通用的例子:

protected static function getMethod($name) 
  $class = new ReflectionClass('MyClass');
  $method = $class->getMethod($name);
  $method->setAccessible(true);
  return $method;


public function testFoo() 
  $foo = self::getMethod('foo');
  $obj = new MyClass();
  $foo->invokeArgs($obj, array(...));
  ...

【讨论】:

抱歉,回复太晚了,我没有直接测试受保护的方法,它是从构造函数调用的(它是当前的代码库)。谢谢。【参考方案2】:

看起来你捕捉到了错误的异常:Zend_Mail 似乎抛出了一个InvalidArgumentException,而你捕捉到了一个Zend_Mail_Exception

试试下面的代码:

protected function setSubject()

    # catch exception thrown if non existing $this->message object property is accessed
    try 
        $this->subject = $this->defunctTheContent($this->message->getHeaders(), $this->message->subject);
    
    catch (InvalidArgumentException $e) 
        $this->subject = '(empty subject)';
    


编辑

再次阅读您的问题,我想说Zend_Mail_Exception 永远不会被抛出。 如果您从第一个代码块中删除 try/catch,我敢打赌它也会起作用:

protected function setSubject()

    $this->subject = $this->defunctTheContent($this->message->getHeaders(), $this->message->subject);
    if (! $this->subject) 
        $this->subject = '(empty subject)';
    

Line 396 指的是不存在的标头,但即使$this->subject 为空(异常类和消息与您的测试结果不匹配),它似乎也不会被触发。我怀疑这个头文件之前已经在 Zend 或其他地方设置为空值。

这可以解释为什么在第二种情况下,$this->subject 永远不会被设置(catch 代码永远不会被执行)。 InvalidArgumentException 可能是由parseEmail 类抛出的,它检测到subject 未设置。

然而,第二个块会无条件地检查! $this->subject,并相应地设置它。所以测试通过了。

总结一下:

Zend_Mail_Exception 永远不会被抛出 InvalidArgumentException 被扔进parseEmail

【讨论】:

我不确定:github.com/dmelo/Zend-1.11/blob/master/Mail/Part.php#L396,无论哪种方式,此代码在单元测试之外使用时都可以正常工作。谢谢。 InvalidArgumentExceptionException 为负数。 好吧,那我误解你的问题了!请参阅我的更新答案。 $this->messageZend_Mail 对象,如果您尝试访问某些不存在的标头(对象属性),实际上会抛出Zend_Mail_Exception,例如subject。我添加了 try/catch,因为未捕获的异常导致了致命错误,但对我来说,主题是可选的。我明白你在说什么,但是,它仍然没有按预期工作。谢谢。附言主题是一个空字符串private $subject = "" 您是否尝试过我更新的答案中的代码?你有例外吗?

以上是关于在 catch 块中设置对象属性时 PHPUnit 测试失败的主要内容,如果未能解决你的问题,请参考以下文章

使用 WSL-2 和 Docker 在 PhpStorm 中设置 PHPUnit:无法解析 PHPUnit 版本输出:无法打开输入文件

在 PHPUnit/DBUnit 中设置外键约束

phpunit 8 及更高版本中设置套件的问题

Javascript 在原型中设置具有值类型的对象属性? [关闭]

查询后在猫鼬对象中设置属性[重复]

查询后在猫鼬对象中设置属性[重复]