在PHPunit中测试异常总是失败的
我在PHP中很少有自定义异常:在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
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)
}