PHPSpec Catching TypeError in PHP7
Asked Answered
P

2

8

I want test an example method with scalar type hinting and strict types in PHP7. When I don't pass an argument, the method should throw a TypeError. PHPSpec return fatal error:

Uncaught TypeError: Argument 1 passed to Example::test

<?php

class Example
{
    public function test(string $name)
    {
        $this->name = $name;
    }
}


class ExampleSpec extends ObjectBehavior
{
    function it_is_initializable()
    {
        $this->shouldHaveType('Test\Example');
    }

    function it_check_test_method_when_not_pass_argument()
    {
        $this->shouldThrow('\TypeError')->during('test');
    }
}

At the beginning I declare: declare(strict_types=1);

What is wrong? How do I test throwing TypeError?

Pownall answered 2/1, 2016 at 17:36 Comment(6)
So the exception is thrown but uncaught? Or it's not being thrown and it should be?Moralez
Method throw TypeError and I want catch TypeError. I want use $this->shouldThrow('\TypeError')->during('test'). This method in PHPSpec works when method return Exception but not TypeError.Pownall
Are you using the very latest version of PHPSpec?Moralez
Version PHPSpec is 2.4.1Pownall
It's possible that this is a bug in PHPSpec, and you should report it to them! TypeError inherits from BaseException rather than Exception, so it's possible that PHPSpec is only catching Exceptions that inherit from Exception.Moralez
Btw check my answer edit. Someone reported it as a bug, you should chime in on it :)Moralez
C
6

For me it works if I annotate the unit test with this:

/**
 * @expectedException \TypeError
 */

Then my test is green.

Caddie answered 4/8, 2017 at 15:34 Comment(1)
This just returns Failed asserting that exception of type "\TypeError" is thrown. now.Subjunction
M
6

Upon further investigation, this is a PHPSpec bug, and has been reported here. The bug hasn't been fixed in several months, so I would suggest commenting on it.

If you look at the code in src/PhpSpec/Matcher/ThrowMatcher.php, you can see that PHPSpec catches Exceptions that inherit 'Exception' and then checks the instance type of that exception. But, TypeError doesn't inherit from Exception, it inherits from Error. The only thing it has in common with an Exception, is that they both implement the Throwable interface.

For example:

101     public function verifyPositive($callable, array $arguments, $exception = null)
102     {
103         try {
104             call_user_func_array($callable, $arguments);
105         } catch (\Exception $e) {
106             if (null === $exception) {
107                 return;
108             }
109
110             if (!$e instanceof $exception) {
111                 throw new FailureException(sprintf(
112                     'Expected exception of class %s, but got %s.',
113                     $this->presenter->presentValue($exception),
114                     $this->presenter->presentValue($e)
115                 ));
116             }

Report the bug, explain these details, and show them this documentation about the inheritance of TypeError.

Moralez answered 3/1, 2016 at 10:10 Comment(2)
I reported that bug. I don't know when this bug will be fixed.Pownall
@Pownall You can catch(Error $e) to catch Errors... or any specific class that interfaces ThrowablePrivilege
C
6

For me it works if I annotate the unit test with this:

/**
 * @expectedException \TypeError
 */

Then my test is green.

Caddie answered 4/8, 2017 at 15:34 Comment(1)
This just returns Failed asserting that exception of type "\TypeError" is thrown. now.Subjunction

© 2022 - 2024 — McMap. All rights reserved.