Hướng dẫn assert no exception phpunit

PHP 7.4 and PHPUnit 9

Using the PHPUnit homepage example (https://phpunit.de/getting-started/phpunit-9.html):

private function ensureIsValidEmail(string $email): void
{
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        throw new InvalidArgumentException(
            sprintf(
                '"%s" is not a valid email address',
                $email
            )
        );
    }
}

The homepage also shows us how to test the exception is thrown using the expectException() method:

public function testCannotBeCreatedFromInvalidEmailAddress(): void
{
    $this->expectException(InvalidArgumentException::class);

    Email::fromString('invalid');
}

That's great. But what if I want to test the exception is not thrown given valid input ?

Looking at the docs (https://phpunit.readthedocs.io/en/9.3/writing-tests-for-phpunit.html#testing-exceptions) there seems to be no mention of an inverse method to expectException() ?

How should I approach this ?

EDIT TO ADD:

Just to make it perfectly clear, I'm looking to test an Email::fromString(''); scenario, i.e. that the exception is not thrown.

asked Sep 1, 2020 at 20:35

Little CodeLittle Code

1,2352 gold badges13 silver badges34 bronze badges

1

If an uncaught or unexpected exception is thrown, the test will fail. You don't have to do anything special, just run the code being tested. If there are no other assertions in the test method, you'll also have to do $this->expectNotToPerformAssertions(); or you'll get a warning that the test doesn't perform any assertions.

public function testCannotBeCreatedFromInvalidEmailAddress(): void
{
    $this->expectNotToPerformAssertions();
    Email::fromString('invalid'); // If this throws an exception, the test will fail.
}

answered Sep 1, 2020 at 20:39

Alex HowanskyAlex Howansky

47.6k8 gold badges74 silver badges95 bronze badges

2

Not the answer you're looking for? Browse other questions tagged php phpunit or ask your own question.

I’m refactoring a legacy PHP codebase, and that includes writing new tests. While doing that, I found a class method that accepts only a predetermined set of values, and refuses any other value by throwing an exception. Below is a simplified representation of this class:



class MyClass
{
    protected $value;

    public function setValue($value)
    {
        if (in_array($value, ['foo', 'bar'])) {
            $this->value = $value;
            return $this;
        }

        throw new RuntimeException("{$value} is not a valid value.");
    }
}

Promptly, I wrote a test to check if the method was filtering out invalid input values:



use PHPUnit\Framework\TestCase;

class MyTestCase extends TestCase
{
    protected $instance;

    public function setUp()
    {
        $this->instance = new MyClass();
    }

    public function testSetValueRefusesBadInput()
    {
        $this->expectException(RuntimeException::class);
        $this->instance->setValue('baz');
    }
}

Easy peasy.

But what if the method is not handling valid input values correctly? Since the method accepts only a small set of values, we could test all of them. However, PHPUnit 6 doesn’t have a doNotExpectException assertion, nor does it allow a test without an assertion.

We can easily overcome these limitations by adding an assertion to the end of the test ($this->assertTrue(true)) or by increasing the assertion count ($this->addToAssertionCount(1)). If the MyClass::setValue method implementation is incorrect, an exception will be thrown, otherwise, the assertion will be accounted for and PHPUnit will not “complain” about the test.



use PHPUnit\Framework\TestCase;

class MyTestCase extends TestCase
{
    protected $instance;

    public function setUp()
    {
        $this->instance = new MyClass();
    }

    public function testSomethingWorks()
    {
        $this->instance->setValue('bar');
        $this->addToAssertionCount(1);
    }

    public function testAnotherThingWorks()
    {
        $this->instance->setValue('foo');
        $this->assertTrue(true);
    }
}