6

我在 PHP 中有几个自定义异常:

class MainException extends Exception {};
class ExceptionOne extends MainException {};
class ExceptionTwo extends MainException {};

我在课堂上以两种简单的方法使用它们:

public function firstFunction($param) {
    if ($some_condition) {
        // do whatever
    } else {
        throw new ExceptionOne();
    }
}

public function secondFunction($param) {
    if ($some_condition) {
        // do whatever
    } else {
        throw new ExceptionTwo();
    }
}

我还对这两个异常进行了 PHPUnit 测试,类似于:

public function testFirstException() {
    try {
        // anything
    } catch (Exception $e) {
        $this->assertType('ExceptionOne', $e);
        $this->assertType('MainException', $e);
    }
}
public function testSecondException() {
    try {
        // anything
    } catch (Exception $e) {
        $this->assertType('ExceptionTwo', $e);
        $this->assertType('MainException', $e);
    }
}

如果我在浏览器中测试我的课程并故意使我的函数失败(使用与 PHPUnit 测试相同的东西),我可以看到ExceptionOneExceptionTwo在需要时提出。但是,当我使用 PHPUnit 对其进行测试时,我总是会失败:

1) testSecondException(SomeTest)
Failed asserting that <PHPUnit_Framework_ExpectationFailedException> is an instance of class "ExceptionTwo".
C:\test.php:67

第 67 行是
$this->assertType('ExceptionTwo', $e);
,无论我尝试什么,它都会失败。我很确定我的情况是secondFunction正确的。第一个测试 ( testFirstException) 完美运行,我从来没有像第二个测试那样失败。
我想补充一点,我不应该在这里更改 PHPUnit 测试!

我在这里做错了什么?

4

3 回答 3

7

看起来你在你的 try/catch 中掩盖了一个不同的错误。如果您的 try 块中有测试断言,并且该断言失败,则将其作为异常抛出。尝试使用setExpectedException而不是 try/catch 块:

public function testFirstException() {
    $this->setExpectedException('ExceptionOne');
    $fixture->firstFunction();
}

您应该将setExpectedException调用放在您希望引发异常的行之前。

另一种选择是使用@expectedExceptiondocblock 注释。

/**
 * @expectedException ExceptionOne
 */
public function testFirstException() {
    $fixture->firstFunction();
}

如果您想保留 try/catch 方法,同样适用:确保 try 块中的唯一行是应该引发异常的行。

于 2012-11-02T15:38:21.210 回答
7

从您的评论到 cbuckley 的出色答案,测试似乎是这样编写的:

public function testFirstException() {
    try {
        // some code that is supposed to throw ExceptionOne
        $this->assertTrue(false, "Test failed");
    } catch (Exception $e) {
        $this->assertType('ExceptionOne', $e);
        $this->assertType('MainException', $e);
    }
}

如果在测试期间没有抛出异常,assertTrue则用于确保测试失败。但是,这不起作用,因为失败的断言会引发不同的异常类型,从而导致错误消息令人困惑。

Failed asserting that <PHPUnit_Framework_ExpectationFailedException> 
is an instance of class "ExceptionOne".

您可以使用@expectedException或来解决此问题setExpectedException。测试不仅会在抛出时通过ExceptionOne,而且在未抛出或抛出其他异常类型时也会失败。

/**
 * @expectedException ExceptionOne
 */
public function testFirstException() {
    // some code that is supposed to throw ExceptionOne
}

当没有抛出异常时,错误消息是

Failed asserting that exception of type "ExceptionOne" is thrown.

当抛出不同类型的异常时,您会看到

Failed asserting that exception of type "Exception" matches
expected exception "RuntimeException".

这种测试异常的方法是

  • 更容易写,
  • 更容易阅读,
  • 测试失败时更容易调试,
  • 并且正确。
于 2012-11-02T16:23:47.253 回答
0

Try {}使用 php 单元,您必须生成关于伪造响应中的任何方法的异常。

public function testFirstFunction() {
....
$this->methodOnGenerateExeption(Argumen::Any())->willReturn()->willThrow(\Exception::class);
$this->setExpectedException(\Exception::class);

  $this->classMockToTest->firstFunction($parameters)
}
于 2019-11-05T20:47:53.903 回答