如何在php单元测试中模拟日期?

时间:2019-12-12 12:07:12

标签: php phpunit

我是php单元测试的新手。如何在下面的函数中模拟日期。当前正在获取当前日期。但是我想将模拟中的日期更改为一个月的第一天。

empty

我尝试这样做,但是没有用。

function changeStartEndDate() {

    if (date('j', strtotime("now")) === '1') {

        $this->startDate = date("Y-n-j", strtotime("first day of previous month"));

        $this->endDate = date("Y-n-j", strtotime("last day of previous month")) . ')';
    } else {

        $this->startDate = date("Y-n-j", strtotime(date("Y-m-01")));
        $this->endDate = date("Y-n-j", strtotime("yesterday"));
    }
}

2 个答案:

答案 0 :(得分:2)

通过避免副作用,单元测试最有效。 datestrtotime都取决于主机系统上定义的外部状态,即当前时间。

一种处理方法是使当前时间成为可注入属性,使您可以“冻结”它或将其设置为特定值。

如果您查看strtotime的定义,则可以设置当前时间:

strtotime ( string $time [, int $now = time() ] ) : int

date相同:

date ( string $format [, int $timestamp = time() ] ) : string

因此,请始终从函数中注入该值,以使代码结果与主机状态分离。

function changeStartEndDate($now) {

    if (date('j', strtotime("now", $now), $now) === '1') {
        ...
        $this->startDate = date("Y-n-j", strtotime(date("Y-m-01", $now), $now));
        $this->endDate = date("Y-n-j", strtotime("yesterday", $now), $now);
    }

您的函数是类的一部分吗?然后,我将使$now成为构造函数的一部分,并将其默认设置为time()。在您的测试用例中,您总是可以注入固定的数字,并且总是返回相同的输出。

class MyClassDealingWithTime {
    private $now;

    public function __construct($now = time()) {
        $this->now = $now;
    }


    private customDate($format) {
        return date($format, $this->now);
    }

    private customStringToTime($timeSring) {
        return strtotime($timeStrimg, $this->now);
    }
}

然后在测试用例中将$ now设置为所需的值,例如通过

$firstDayOfAMonth = (new DateTime('2017-06-01'))->getTimestamp();
$testInstance = new MyClassDealingWithTime(firstDayOfAMonth);

$actual = $testInstance->publicMethodYouWantTotest();

... 

答案 1 :(得分:0)

<块引用>

免责声明:我编写了这个库

我正在添加一个答案,以提供一种替代方法,该方法对您的代码进行零修改,无需注入当前时间。

如果您有能力安装 php uopz 扩展,那么您可以使用 https://github.com/slope-it/clock-mock

然后,您可以在测试期间使用 ClockMock::freezeClockMock::reset 将内部 php 时钟“移动”到特定时间点。

相关问题