Unit testing 强制PHPUnit测试引发异常
我对一般的单元测试非常陌生,尤其是PHPUnit,所以如果这是一个简单的问题,请原谅我。我在谷歌上搜索过,但我不知道该搜索什么 所以我有一个函数:Unit testing 强制PHPUnit测试引发异常,unit-testing,phpunit,Unit Testing,Phpunit,我对一般的单元测试非常陌生,尤其是PHPUnit,所以如果这是一个简单的问题,请原谅我。我在谷歌上搜索过,但我不知道该搜索什么 所以我有一个函数: function convert_timezone($dt, $tzFrom, $tzTo, $format) { $newDate = ''; $tzFromFull = timezone_name_from_abbr($tzFrom); $tzToFull = timezone_name_from_abbr($tzTo)
function convert_timezone($dt, $tzFrom, $tzTo, $format) {
$newDate = '';
$tzFromFull = timezone_name_from_abbr($tzFrom);
$tzToFull = timezone_name_from_abbr($tzTo);
if( $tzFromFull != $tzToFull ) {
$dtFrom = new DateTimeZone($tzFromFull);
$dtTo = new DateTimeZone($tzToFull);
try {
// find the offsets from GMT for the 2 timezones
$current = new DateTime(date('c',$dt));
$offset1 = $dtFrom->getOffset($current);
$offset2 = $dtTo->getOffset($current);
$offset = $offset2 - $offset1;
// apply the offset difference to the current time
$newDate = date($format, $current->format('U') + $offset);
} catch (Exception $e) {
$newDate = date($format.' (T)', $dt);
}
} else {
$newDate = date($format, $dt);
}
return $newDate;
}
function test_convert_timezone() {
$dt = mktime(0,0,0,1,1,2000);
$tzFrom = 'CDT';
$tzTo = 'EDT';
$format = 'd/m/Y g:i a';
$result = convert_timezone($dt, $tzFrom, $tzTo, $format);
$this->assertEquals($result, '01/01/2000 1:00 am');
}
下面是测试函数:
function convert_timezone($dt, $tzFrom, $tzTo, $format) {
$newDate = '';
$tzFromFull = timezone_name_from_abbr($tzFrom);
$tzToFull = timezone_name_from_abbr($tzTo);
if( $tzFromFull != $tzToFull ) {
$dtFrom = new DateTimeZone($tzFromFull);
$dtTo = new DateTimeZone($tzToFull);
try {
// find the offsets from GMT for the 2 timezones
$current = new DateTime(date('c',$dt));
$offset1 = $dtFrom->getOffset($current);
$offset2 = $dtTo->getOffset($current);
$offset = $offset2 - $offset1;
// apply the offset difference to the current time
$newDate = date($format, $current->format('U') + $offset);
} catch (Exception $e) {
$newDate = date($format.' (T)', $dt);
}
} else {
$newDate = date($format, $dt);
}
return $newDate;
}
function test_convert_timezone() {
$dt = mktime(0,0,0,1,1,2000);
$tzFrom = 'CDT';
$tzTo = 'EDT';
$format = 'd/m/Y g:i a';
$result = convert_timezone($dt, $tzFrom, $tzTo, $format);
$this->assertEquals($result, '01/01/2000 1:00 am');
}
当我直接在Netbeans中运行测试时,测试通过了。但是当我使用命令行选项生成代码覆盖率报告时,它告诉我这个函数没有完全覆盖,因为测试没有遇到异常
我知道如果我可以改变原来的函数,我可以强迫它抛出一个错误。但我不能那样做。我需要一种方法,在测试函数中,传递一些东西,使被测试的函数遇到异常。我从哪里开始?您几乎无法按照代码的状态测试该分支 您的try-catch块实际上没有捕获任何异常。(
date
抛出一个未被捕获的错误。getOffset
也没有)讽刺的是,如果传入一个不合适的时区常量,则new DateTimeZone
可以。因此,如果您可以重构它并传入未列为有效的时区,您可以得到异常(您应该这样做,因为您似乎打算在这里捕获异常)
那么测试就要开始了
function test_convert_timezone() {
$dt = mktime(0,0,0,1,1,2000);
$tzFrom = 'foo';
$tzTo = 'EDT';
$format = 'd/m/Y g:i a';
$result = convert_timezone($dt, $tzFrom, $tzTo, $format);
$this->assertEquals($result, '01/01/2000 1:00 am');
}
在这个测试中,timezone\u name\u from_abbr
将返回false
,这将导致DateTimeZone
构造函数抛出到达分支的异常
在我看来,您希望避免构造要在函数中使用的对象。对于这段代码,我将传入两个DateTimeZone对象以及一个DateTime对象,并对它们执行操作。将这些其他对象的创建移动到不同的函数/类中。通过这种方式,您可以模拟DateTimeZone和DateTime对象本身,并对正在发生的事情有更多的控制。这段代码并不太糟糕,但它可能会在尝试测试其他东西时造成麻烦
另外,在捕获代码中的一般异常时要小心。如果在try-catch块中使用模拟对象,那么代码可以捕获FailedTestException(当没有使用正确的参数或类似参数调用模拟时抛出),它将被代码捕获。让你的考试看起来是通过的,而实际上不是。由于代码和模拟的缺乏,这里也不是问题,但我想让您知道这一点。Erm。。。如果您只是使用会导致DateTime引发异常的数据创建另一个测试,然后使用PHPUnit检查预期结果(在
catch
block中的语句),会怎么样?我们正在一个已经构建的站点上实施单元测试,所以不-我们不能基于测试编写代码。至于写另一个测试,正如我所说的,我在这方面很新。对于一个被测试的函数,有多个测试函数是合乎道德的吗?当然。如果您的函数有分支,如何在一个测试中检查所有分支?在一个测试中有多个断言是不合适的,因为它违背了测试隔离的原则(查看由开始的讨论以了解有关该原则的详细信息)。如果我编写了一个专门设计用来抛出错误的测试,这不会导致测试失败吗?如何编写一个“成功”结果基于实际函数失败的测试?实际上,您可以在PHPUnit测试中检查异常(例如使用@expectedException
注释)。但关键是,您不必这样做,因为您的函数不会抛出异常-它使用$newDate=date($format.'(t)'$dt)处理异常代码>行。现在,您的任务是进行符合这一行的测试-也就是说,将导致new DateTime
引发异常。感谢您提供的详细答案。以后我会记住的。不幸的是,对于这一轮测试,我们根本无法更改源代码。我们需要编写测试来涵盖代码的现状。