11

根据PHPUnit Documentation on @expectedExceptionMessage,该字符串只能是实际Exception抛出的子字符串。

在我的一种验证方法中,每个发生的错误都会推送一个数组项,并Exception通过内爆错误数组来显示最终消息。

class MyClass
{
    public function validate($a, $b, $c, $d)
    {
        if($a < $b) $errors[] = "a < b.";
        if($b < $c) $errors[] = "b < c.";
        if($c < $d) $errors[] = "c < d.";

        if(count($errors) > 0) throw new \Exception(trim(implode(" ", $errors)));
    }
}

我在这里遇到的问题是,在 PHPUnit 测试方法中,我检查了不同的组合。这会导致我打算失败的测试通过。

/**
 * @expectedException \Exception
 * @expectedExceptionMessage a < b.
 */
public function testValues_ALessBOnly()
{
    $myClass = new MyClass()
    $myClass->validate(1, 2, 4, 3);
}

消息的字符串Exception实际上是"a < b. b < c.",但这个测试仍然通过。我打算让这个测试失败,因为这个消息不是我所期望的。

PHPUnit 有没有办法期望一个确切的字符串,而不是一个子字符串?我希望避免以下情况:

public function testValues_ALessBOnly()
{
    $myClass = new MyClass()
    $fail = FALSE;

    try
    {
        $myClass->validate(1, 2, 4, 3);
    }
    catch(\Exception $e)
    {
        $fail = TRUE;
        $this->assertEquals($e->getMessage(), "a < b.";
    }

    if(!$fail) $this->fail("No Exceptions were thrown.");
}
4

6 回答 6

10

发布此问题时,PHPUnit v3.7 没有解决此问题的方法。较新版本有一个新@expectedExceptionMessageRegExp选项,您可以使用该选项添加正则表达式以匹配异常消息。

您的情况,使用^and$强制字符串完全符合预期,可能如下所示:

/**
 * @expectedException \Exception
 * @expectedExceptionMessageRegExp /^a < b\.$/
 */
public function testValues_ALessBOnly()
{
    $myClass = new MyClass()
    $myClass->validate(1, 2, 4, 3);
}
于 2017-05-11T21:22:54.673 回答
9

你可以$this->expectExceptionMessage()用来处理这个。

例子:

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Some error message');
于 2020-03-23T09:09:28.867 回答
3

如果您的测试类 extends PHPUnit_Framework_TestCase,您应该能够使用setExpectedException方法:

    /**
     * @param mixed  $exceptionName
     * @param string $exceptionMessage
     * @param int    $exceptionCode
     *
     * @since  Method available since Release 3.2.0
     */
    public function setExpectedException($exceptionName, $exceptionMessage = '', $exceptionCode = null)
    {
        $this->expectedException        = $exceptionName;
        $this->expectedExceptionMessage = $exceptionMessage;
        $this->expectedExceptionCode    = $exceptionCode;
    }

它允许您单独断言异常类、异常消息甚至异常代码。

于 2017-10-25T13:20:27.953 回答
2

我尝试了很多方法来测试异常,最后我发现测试异常的最好方法是 try-catch 块。我建议你用异常代码抛出异常,然后测试是否抛出了这个代码的异常。例如假设您的异常代码是 101

if(count($errors) > 0) throw new \Exception(trim(implode(" ", $errors)), 101);

例如假设您的异常代码是 101

try {
    $myClass->validate(1, 2, 4, 3);
    $this->fail( "Exception with 101 code should be thrown" );
} catch (Exception $e) {
    $this->assertEquals( 101, $e->getCode());
}
于 2013-09-06T10:38:51.433 回答
0

我通常不担心异常的文本,但会抛出异常本身,因此可以使用@expectedException,甚至是大多数错误场景的数据提供程序。

然后我所做的另一个更改是在不同的函数中进行测试 (a < b),如果发生故障,则抛出异常,而不是将它们全部组合并查看文本。然后也可以自行测试不同的功能。

通过阅读 PHPUnit 手册,即使在 assert 上抛出的错误也使用了“包含”这个词,因此它暗示它是一个子字符串匹配。同样的手册建议像上面那样编写测试,所以我相信只要你想检查异常文本,那么根据 PHPUnit 手册中的示例,你需要像你一样编写测试。

我还要注意比较实际文本,以防您将来添加多种语言支持,然后测试需要理解返回的不同语言/句子。简单地检查异常是否被抛出,不会遇到这个问题。

于 2013-09-06T14:44:23.293 回答
0

另一种可能的解决方案,以确保发生错误:

        $errorHappened = false;
        try {
            //call your code here 
        } catch (\Exception $e) {
            $errorHappened = true;
            $this->assertEquals($e->getMessage(), "Expected error text");
            $this->assertEquals($e->getCode(), "Expected error code");
        }
        $this->assertTrue($errorHappened);
于 2019-10-09T14:50:17.950 回答