在PHPunit中测试异常总是失败的

在PHPunit中测试异常总是失败的,php,exception,phpunit,Php,Exception,Phpunit,我在PHP中很少有自定义异常: class MainException extends Exception {}; class ExceptionOne extends MainException {}; class ExceptionTwo extends MainException {}; 我在课堂上用了两种简单的方法: public function firstFunction($param) { if ($some_condition) { // do what

我在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测试相同的东西),我可以看到
ExceptionOne
exceptionwo
在需要时被提出。然而,当我用PHPUnit测试它时,我总是失败:

1) testSecondException(SomeTest)
Failed asserting that <PHPUnit_Framework_ExpectationFailedException> is an instance of class "ExceptionTwo".
C:\test.php:67
1)testSecondException(SomeTest)
断言类“ExceptionTwo”的实例失败。
C:\test.php:67
第67行是
$this->assertType('ExceptionTwo',$e)
不管我怎么尝试,它都失败了。我很确定我在
secondFunction
中的状态是正确的。第一个测试(
testFirstException
)运行得很好,我从来没有像第二个测试那样失败过。
我想补充一点,我不应该在这里改变PHPUnit测试


我做错了什么???

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

public function testFirstException() {
    $this->setExpectedException('ExceptionOne');
    $fixture->firstFunction();
}
您应该将
setExpectedException
调用放在期望引发异常的行之前

另一种选择是使用
@expectedException
docblock注释

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

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

从您对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".
当没有引发异常时,将显示错误消息

Failed asserting that exception of type "ExceptionOne" is thrown.
当抛出不同类型的异常时,您将看到

Failed asserting that exception of type "Exception" matches
expected exception "RuntimeException".
这种测试异常的方法是

  • 更容易写
  • 更容易阅读
  • 测试失败时更容易调试
  • 而且正确

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

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

  $this->classMockToTest->firstFunction($parameters)
}

此外,如果使用try/catch方法并使用PHPUnit 3.6或更高版本,则应使用assertInstanceOf而不是assertType。这是根据phpunit文档本身,因为assertType已被弃用。。。但我会试着这么做,看看会发生什么…嗯。。。因此,在测试函数的两个
try
块中都有两行代码:一行是从我的类调用方法,另一行是
$this->assertTrue(false,“Some message”)。如果我从
testSecondException
中删除第二个异常,那么一切都会正常工作。。。尽管如此,我认为我真的不应该因为几个不同的原因而更改测试文件中的代码。。。还有什么我可以试试的吗?为什么
testFirstException
try
块中有两行代码时可以正常工作/你需要修正你的测试。失败的断言通过引发异常进行标记。在这种情况下,您不应该捕获泛型异常。为什么你不想改变你的测试?try/catch方法给您带来了问题。至少,更新要像(即,不要捕获一般异常,也不要执行
assertTrue(false)
)!我懂了。。。哦,非常感谢你的帮助!关于改变测试本身。。。我得到了一个任务来编写这个类,并用已经为我编写的PHPUnit测试它。。。任务描述中没有说明“测试代码时有错误”,所以我想我不应该碰它:)是的,我的
try
块就是这样在测试中编写的。现在我不确定我自己了,我会再次检查我的班级…GRRRR!!!我的正则表达式模式中的一个愚蠢的输入错误一直在导致这种情况>(我现在真的感觉像个傻瓜:)无论如何,再次感谢所有这些关于测试异常的伟大信息,在将来一定要记住这一点!我强烈建议您与编写该测试的人分享此建议。你本可以从所有这些痛苦中解脱出来。+1为了让我的答案更清楚:-)FWIW,我不建议使用
@expectedException
,因为它只声明在测试代码中的某个地方抛出了这样的异常。如果使用
setExpectedException
,您可以通过将异常放在预期失败的行之前来精确控制何时抛出异常。呵呵,David,我当然会这样做:)不幸的是,这最终是我的代码中的错误,即使我在PHPUnit方面没有太多经验,我很清楚这一点。。。正如本德所说:学习很有趣
public function testFirstFunction() {
....
$this->methodOnGenerateExeption(Argumen::Any())->willReturn()->willThrow(\Exception::class);
$this->setExpectedException(\Exception::class);

  $this->classMockToTest->firstFunction($parameters)
}