1

all...my subject says it all. I'm trying to do a test that actually intentionally makes "Invalid argument supplied for foreach()" happen. I'm trying to get PHPUnit to expect it, but...nope, my tests still come to a screeching halt. The reason: "invalid argument supplied for foreach()" right at the exact point where I'm telling it that it's going to happen.

At the top of my file I have:

use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Error\Error;
use PHPUnit\Framework\Error\Notice;
use PHPUnit\Framework\Error\Warning;

My class declaration starts with:

Class flirzelkwerpTest extends TestCase {

Here are the lines in the test file:

    // Let's try to add nothing.
    // (It should throw an error because of "Invalid argument supplied for foreach()" in barabajagal.php.)
    $this->expectException(\InvalidArgumentException::class);
    $this->expectExceptionMessage('Invalid argument supplied for foreach()');
    $resp = $barabajagal->add();

The error happens on that last line. Shouldn't the previous two lines be telling PHPUnit, "Hey, bub, I expect there to be an error here, and this is the message you should be getting verbatim"??

We're using PHP 7.3.4 and PHPUnit 8.3.2.

dauber
  • 330
  • 6
  • 20
  • It's unclear what you're asking. The test expects an InvalidArgumentException to be thrown by `$resp = $barabajagal->add();`. What do you mean by "screeching halt"? Is there an error? What do you expect to happen? There isn't enough information to debug whatever the issue is. – Gerard Roche Oct 03 '19 at 17:59
  • PHPunit returns with an error. All assertions up to -- but not including -- this one happen, and I get a message from PHPunit saying "There was 1 error: 1) flirzelkwerpTest::testAdd / Invalid argument supplied for foreach() " --- I thought the whole point of expecting an error was that PHPUnit wouldn't crap out on it, no? The whole point is that I want PHPUnit to note that that error is coming up, expect it, and continue with the remaining tests -- which it does not. I don't know what other information you'd need. – dauber Oct 03 '19 at 18:16
  • I think you might have one of the `--stop-on-failure`, `--stop-on-error`, etc. flags enabled see https://phpunit.readthedocs.io/en/8.3/textui.html. Also see the configuration options like `stopOnFailure`, `stopOnError`, etc https://phpunit.readthedocs.io/en/8.3/configuration.html – Gerard Roche Oct 03 '19 at 18:28
  • Good call -- let me check that. Thanks! – dauber Oct 03 '19 at 18:40
  • (UPDATE: there's no phpunit.xml file on my computer anywhere. Maybe I should fix that...) – dauber Oct 03 '19 at 18:48
  • OK, just set those in the phpunit.xml (which I've confirmed is loading -- the giveaway is that I have "colors" set to "true"), but...nope, still crapping out on the foreach(). (And those attributes are set to false by default anyway, so even without that xml, it wouldn't have mattered. :( ) – dauber Oct 03 '19 at 19:38
  • I don't know why the test run is stopping at that particular test. It sounds like the code in question is exiting or causing a fatal error. I don't see how `$this->expectException(\InvalidArgumentException::class);` would work anyway. It should be expecting the warning exception provided by PHPUnit `$this->expectException(Warning::class)`. PHPUnit converts errors, warnings, and notices to exceptions (https://phpunit.readthedocs.io/en/8.3/writing-tests-for-phpunit.html#testing-php-errors). – Gerard Roche Oct 03 '19 at 20:03
  • Yeah, that's what I thought, but even using Warning::class produces the same result. :/ But...the PHP error log shows nothing more than just a warning about the invalid argument. Maybe I'm over-testing because in reality, we don't have any situations that would ever make that argument an empty array. – dauber Oct 03 '19 at 20:10
  • I assume when you comment out that test it works fine. Try substituting the code with this `foreach (null as $value) {}`. I'm also posting more details below. – Gerard Roche Oct 03 '19 at 20:15
  • Okay...just so I'm clear, the expectation of errors only counts if the loop is in the test itself and not the raw code that it's actually testing? Because when I put in your sample, the "testForeachWarning" function's test passes with flying colors... And yes, the test works fine if I comment out the call to the function that's giving me the forEach() warning. – dauber Oct 03 '19 at 21:04
  • Of course, my last comment just made me think: just fix the frickin' issue in the existing code. Even though our current code will never result in the situation that would result in that foreach() warning, nothing's preventing it from having that happen later. Problem solved. :) – dauber Oct 03 '19 at 21:21
  • 1
    You're expecting the code `$barabajagal->add();` to raise a warning, just like the code I provided, but obviously it's not doing what you expect it to do. There's nothing wrong with the test. The problem is: `$barabajagal->add();`. It's not doing what you expect it to do. **The test has actually found a bug in your code.** – Gerard Roche Oct 03 '19 at 21:23

1 Answers1

5

When Testing PHP Errors there three things to be aware of 1) ensure that PHPUnit is converting PHP errors, warnings, and notices to exceptions, 1) ensure that PHP's error reporting is set appropriately, and 3) use the exceptions that PHPUnit converts the errors, warnings, and notices to.

1) ensure PHPUnit is converting errors, warnings, and notices

By default, PHPUnit converts PHP errors, warnings, and notices that are triggered during the execution of a test to an exception. Using these exceptions, you can, for instance, expect a test to trigger a PHP error as shown in Example 2.12.

Testing PHP Errors

2) Ensure PHP's error reporting is set

PHP’s error_reporting runtime configuration can limit which errors PHPUnit will convert to exceptions. If you are having issues with this feature, be sure PHP is not configured to suppress the type of errors you’re testing.

Testing PHP Errors

3) Use the converted exceptions provided by PHPUnit

<?php

namespace Sandbox\Stackoverflow;

use PHPUnit\Framework\Error\Warning;

class Q58222995Test extends \PHPUnit\Framework\TestCase
{
    public function testForeachWarning()
    {
        $this->expectException(Warning::class);
        $this->expectExceptionMessage('Invalid argument supplied for foreach()');

        $collection = null;
        foreach ($collection as $value) {}
    }
}
Gerard Roche
  • 6,162
  • 4
  • 43
  • 69