我对一般的单元测试和特别是PHPUnit都很陌生,所以如果这是一个简单的问题,请原谅我。我做了一些谷歌搜索,但我不知道要知道要搜索什么。
所以我有一个功能:
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中运行测试时,测试通过。但是当我使用命令行选项生成代码覆盖率报告时,它告诉我这个功能没有被完全覆盖,因为测试没有达到异常。
我知道如果我可以改变原来的功能,我可以强迫它抛出一个错误。但我无法做到这一点。我需要一种方法,在测试函数中传递一些东西,这将使被测试的函数达到其异常。我从哪里开始?
答案 0 :(得分:1)
你几乎无法像代码那样测试那个分支。
你的try-catch块实际上并没有捕获任何异常。 (date
会抛出一个未捕获的错误。getOffset
也没有。如果传入的时区常量不合适DateTimeZone::__construct(),可能会讽刺new DateTimeZone
。因此,如果您可以重构它并传入未列为有效的时区,您可以获得异常(您应该看到这是因为您希望在此处捕获异常)。
function convert_timezone($dt, $tzFrom, $tzTo, $format) {
$newDate = '';
$tzFromFull = timezone_name_from_abbr($tzFrom);
$tzToFull = timezone_name_from_abbr($tzTo);
if( $tzFromFull != $tzToFull ) {
try {
$dtFrom = new DateTimeZone($tzFromFull);
$dtTo = new DateTimeZone($tzToFull);
// 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 = '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_name_from_abbr
将返回false
,这将导致DateTimeZone
构造函数抛出异常到达您的分支。
IMO,您希望避免构建要在函数中使用的对象。对于此代码,我将传递两个DateTimeZone对象以及DateTime对象并对它们执行操作。将这些其他对象的创建移动到不同的函数/类中。这样,您可以模拟DateTimeZone和DateTime对象本身,并可以更好地控制发生的事情。这段代码不是太糟糕,但是在尝试测试其他东西时可能会造成麻烦。
另外,请注意在代码中捕获泛型异常。如果在try-catch块中使用模拟对象,则代码可以捕获FailedTestException(在未使用正确的参数或类似函数调用模拟时抛出),这将由您的代码捕获。让它看起来像你的测试实际上没有通过。由于代码和缺少模拟,这里不再是问题,但我想让你意识到它。