Home » Php » php – PHPUnit test fails when setting object property within catch block

php – PHPUnit test fails when setting object property within catch block

Posted by: admin July 12, 2020 Leave a comment

Questions:

I’m testing setSubject method which sets subject to (empty subject) if it is missing.
Zend_Mail throws exception if undeclared property is trying to be accessed (e.g. email subject is missing, better throw some exceptions). More info: http://framework.zend.com/issues/browse/ZF-11371
This is what I need to use to be able to test it successfully:

Class

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)';
}

Test

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

However, you can see that catch block is empty, if I try this code…

protected function setSubject()
{
    try
    {
      $this->subject = $this->defunctTheContent($this->message->getHeaders(), $this->message->subject);
    }
    catch (Zend_Mail_Exception $e)
    {
      $this->subject = '(empty subject)';
    }
}

Test fails with message:

There was 1 error:

1) Email_ParseTest::testNoSubject
InvalidArgumentException: subject is required

It complains that $this->subject is not set (or similar).

Some more info:

  • PHP 5.4.8
  • Zend Framework 1.9.5
  • PHPUnit 3.6.12
  • subject is defined as empty string ("")

I’ve tested second method “by hand”, and it is working as expected (subject is set within catch block). I don’t have much experience with PHPUnit so this might be E_PEBKAC easily.

How to&Answers:

Unless i’m misunderstanding your question, you’re attempting to test a protected method… you can’t do that this way. Protected and private methods are suppose to be tested by testing the public methods that use them.

If you’re using PHP 5.3.2+ with PHPUnit, you can test your private and protected methods directly by using reflection to set them to be public prior to running your tests, however, as I’ve mentioned, you’re suppose to test public methods.

But if you want to use reflection, here’s a generic example:

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(...));
  ...
}

Answer:

Looks like you’re catching the wrong exception: Zend_Mail seems to throw an InvalidArgumentException, while you’re catching a Zend_Mail_Exception.

Try the following code:

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)';
    }
}

Edit

Reading again your question, I’d say that Zend_Mail_Exception is never thrown.
If you remove the try/catch from the first block of code, I’d bet it will work as well:

protected function setSubject()
{
    $this->subject = $this->defunctTheContent($this->message->getHeaders(), $this->message->subject);
    if (! $this->subject) {
        $this->subject = '(empty subject)';
    }
}

Line 396 refers to a non-existing header, but it looks like it’s not triggered even when $this->subject is empty (the exception class & message do not match your test result). I suspect that this header has been set before, in Zend or somewhere else, to an empty value.

That would explain why, in the second case, $this->subject is never set (the catch code is never executed). The InvalidArgumentException is probably thrown by the parseEmail class, which detects that subject is not set.

The second block, however, does unconditionally check for ! $this->subject, and sets it accordingly. So the test passes.

To summarize:

  • Zend_Mail_Exception is never thrown
  • InvalidArgumentException is thrown in parseEmail