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

时间:2015-01-07 13:14:17

标签: php cakephp phpunit cakephp-2.0

我正在测试User::validateAdmin()模型方法,该方法可以做三件事:

  • 如果有效的管理员,请返回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用法,无论是否预期。

正确测试我的三个场景的正确性是什么?

2 个答案:

答案 0 :(得分:2)

你应该保持你的测试简短和干净。因此,您绝对应该将测试分成多个测试,以测试方法的不同方面。

我也鼓励你以BDD风格编写测试。所以你应该测试预期的行为,例如:

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

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

    //then
    $this->assertTrue($result);
}

在PhpUnit中很难测试此样式的异常。

您可以尝试CatchException中的ouzo goodies

public function shouldFailIfNotAdmin() {
    //given
    $anotherUserRole = ........;

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

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

答案 1 :(得分:0)

正如PHPUnit doesn't continue test after expecting an exception所解释的那样,问题中显示的方法存在缺陷,因为PHPUnit将测试包装在常规的try / catch块中,因此只要抛出异常,测试方法中的其余断言就是忽略。除此之外,\PHPUnit_Framework_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);
}