19

I am trying to validate that a php7 function accept only integers.

This is the class:

<?php

declare(strict_types=1);

class Post
{
    private $id;

    public function setId(int $id)
    {
        $this->id = $id;
    }
}

And this is the test:

<?php

declare(strict_types=1);

class PostTest extends \PHPUnit_Framework_TestCase
{
    private function getPostEntity()
    {
        return new Post();
    }

    public function testSetId()
    {
        $valuesExpected = [123, '123a'];
        foreach ($valuesExpected as $input) {
            $this->getPostEntity()->setId($input);
        }
    }
}

The error I get is:

TypeError: Argument 1 passed to Post::setId() must be of the type integer, string given, called in /path/test/PostTest.php on line 35

Is it possible to validate such error? also, does it make any sense to run such a check?

michaelbn
  • 7,393
  • 3
  • 33
  • 46

6 Answers6

24

Yes, you can test for TypeError the same way you would use for any other exception.

However, I would not test that PHP emits a type error in case of a type mismatch. This is the kind of test that becomes superfluous with PHP 7 code.

Sebastian Bergmann
  • 7,837
  • 1
  • 27
  • 35
  • Could you give details about the superflous aspect of testing type mismatch? Why is it useless to check that I did not forget to add a type hint to `myMethod()`'s first argument, for instance? – marcv Oct 11 '17 at 16:26
  • 1
    This does not appear to be the case. From your own documentation: `By default, PHPUnit converts PHP errors, warnings, and notices that are triggered during the execution of a test to an exception.` It seems you would need `@expectedException PHPUnit\Framework\Error` to expect any PHP `Error`s (including `Error`s emitted via PHP 7 `assert()`), which is counter-intuitive to say the least. – chili Jan 23 '18 at 05:35
  • could you explain (maybe with a documentation referral) how to solve this problem? https://stackoverflow.com/questions/48486568/catch-an-error-as-exception – Michele Carino Jan 28 '18 at 13:17
9

Try this:

$this->expectException(TypeError::class);
  • Any useful reference? doc and etc? – michaelbn Jun 01 '17 at 08:45
  • 1
    That doesn't fix anything because as mentioned above TypeError is NOT a subclass of Exception. – Calamity Jane Aug 04 '17 at 14:06
  • @CalamityJane it certainly is at least in PHP 7.2 – Geoffrey Aug 12 '19 at 04:37
  • in 2017 I worked with Php7.0, glad if it is fixed in PHP 7.2! – Calamity Jane Aug 12 '19 at 13:11
  • 1
    `$this->expectException(TypeError::class);` did worked in PHP 7.0.33, 7.1.33, 7.2.30, 7.3.17 and 7.4.5. Here's the proven repo: https://github.com/KEINOS/Practice_PHPUnit-test-of-TypeHint Thanks. But unfortunately @pawel-ploczek's `$this->expectError(TypeError::class);` did not even the latest PHP (7.4.5). – KEINOS Apr 28 '20 at 07:06
5

Sadly, TypeError is not a subclass of Exception (reference), whilst it extends Error. The only thing they are really sharing is the the Throwable interface. The ThrowMatcher can't actually catch a TypeError.

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.

See also this answer.

Community
  • 1
  • 1
sentenza
  • 1,608
  • 3
  • 29
  • 51
2

For newer PHP versions try:

$this->expectError(TypeError::class);
1

Just use :

$this->expectError(TypeError::class);

But dont forget to put it BEFORE your function call

0

I had a similar situation and was trying to catch the TypeError, but PHP wasn't throwing it at all. It turned out, that for some reason error_reporting directive was set to exclude E_NOTICE.

When I set error_reporting = E_ALL & ~E_DEPRECATED in php.ini, it started to work as expected. So, just make sure the likes of E_ERROR, E_WARNING, E_NOTICE are not excluded in your error_reporting setup.

pstryk
  • 1,991
  • 1
  • 14
  • 11