Php 测试可能返回异常的方法的正确方法

Php 测试可能返回异常的方法的正确方法,php,cakephp,phpunit,cakephp-2.0,Php,Cakephp,Phpunit,Cakephp 2.0,我正在测试一个User::validateAdmin()model方法,它可以做三件事: 如果管理员有效,则返回true 如果管理员过期,则返回false 如果不是管理员,则抛出NotAnAdminException 到目前为止,我有: $result = $this->User->validateAdmin($validAdmin); $espected = true; $this->assertEquals($result, $espected); $result =

我正在测试一个
User::validateAdmin()
model方法,它可以做三件事:

  • 如果管理员有效,则返回
    true
  • 如果管理员过期,则返回
    false
  • 如果不是管理员,则抛出
    NotAnAdminException
到目前为止,我有:

$result = $this->User->validateAdmin($validAdmin);
$espected = true;
$this->assertEquals($result, $espected);

$result = $this->User->validateAdmin($disabledAdmin);
$espected = false;
$this->assertEquals($result, $espected);

$this->setExpectedException('NotAnAdminException');
$result = $this->User->validateAdmin($anotherUserRole);
$espected = null;
$this->assertEquals($result, $espected);
$this->setExpectedException(null);
。。。但这使得PHPUnit忽略所有后续的
NotAnAdminException
用法,无论预期与否

正确地测试我的三个场景的正确方法是什么?

正如所解释的,问题中显示的方法是有缺陷的,因为PHPUnit将测试包装在一个常规的try/catch块中,所以一旦抛出异常,测试方法中的其余断言就会被忽略。除此之外,
\PHPUnit\u Framework\u TestCase::setExpectedException
方法按预期工作:当且仅当抛出给定异常时,测试才会通过

最干净的方法是用不同的方法分割断言:

public function testvalidateAdminValid(){
    $validAdmin = ........;
    $result = $this->User->validateAdmin($validAdmin);
    $espected = true;
    $this->assertEquals($result, $espected);
}

public function testvalidateAdminExpired(){
    $disabledAdmin = ........;
    $result = $this->User->validateAdmin($disabledAdmin);
    $espected = false;
    $this->assertEquals($result, $espected);
}

public function testvalidateAdminNotAnAdmin(){
    $anotherUserRole = ........;
    $this->setExpectedException('NotAnAdminException');
    $this->User->validateAdmin($anotherUserRole);
}
如果您希望将所有相关测试都粘贴到同一个方法中,则必须自己模拟
setExpectedException
,例如:

try{
    $result = $this->User->validateAdmin($anotherUserRole);
    $this->fail('Failed to throw NotAnAdminException');
}catch(NotAnAdminException $e){
    $this->assertEmpty($result);
}

你应该保持你的测试简短干净。因此,您应该明确地将测试分为多个测试,这些测试测试方法的不同方面

我还鼓励您以风格编写测试。因此,您应该测试预期行为,例如:

public function shouldReturnTrueForAdmin() {
    //given
    $validAdmin = ........;

    //when
    $result = $this->User->validateAdmin($validAdmin);

    //then
    $this->assertTrue($result);
}
在PhpUnit中,以这种方式测试异常是很困难的

您可以从以下位置进行尝试:


看起来你已经把这些都放在一个测试里了?是的,把抛出异常的东西放到一个测试用例方法中,并通过文档块注释进行断言。@ndm-感谢链接,它清楚地解释了为什么我的方法是错误的。我知道我需要尝试/捕获自己,或者将测试代码拆分为不同的方法(不知道是否有首选方法,或者这只是首选问题)。@mark-我认为这将只测试每个测试方法中的第一个断言,不是吗?此外,如果异常没有在应该抛出的时候抛出,我需要使测试失败。或者简单地使用doc块注释样式
@expectedException
public function shouldFailIfNotAdmin() {
    //given
    $anotherUserRole = ........;

    //when
    CatchException::when($this->User)>validateAdmin($anotherUserRole);

    //then
    CatchException::assertThat()->isInstanceOf("NotAnAdminException");
}