Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Unit testing 强制PHPUnit测试引发异常_Unit Testing_Phpunit - Fatal编程技术网

Unit testing 强制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)

我对一般的单元测试非常陌生,尤其是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');
}
下面是测试函数:

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
引发异常。感谢您提供的详细答案。以后我会记住的。不幸的是,对于这一轮测试,我们根本无法更改源代码。我们需要编写测试来涵盖代码的现状。