为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

PHP
沧海一幻觉 2022-06-17 09:55:01
我是 php 单元测试的新手。如何在下面的函数中模拟日期。目前它正在获取当前日期。但我想将模拟中的日期更改为一个月的第一天。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"));    }}我试过这样做,但它不起作用。public function testServicesChangeStartEndDate() {    $mock = $this->getMockBuilder('CoreFunctions')        ->setMethods(array('changeStartEndDate'))        ->getMock();    $mock->method('changeStartEndDate')        ->with(date("Y-n-j", strtotime(date("Y-m-01"))));    $this->assertSame(        '1',        $this->core->changeStartEndDate()    );}
查看完整描述

2 回答

?
猛跑小猪

TA贡献1858条经验 获得超8个赞

通过避免副作用,单元测试效果最好。两者date都strtotime取决于在您的主机系统上定义的外部状态,即当前时间。


解决这个问题的一种方法是使当前时间成为可注入属性,允许您“冻结”它或将其设置为特定值。


如果您查看它的定义,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();




查看完整回答
反对 回复 2022-06-17
?
收到一只叮咚

TA贡献1821条经验 获得超4个赞

免责声明:我写了这个库

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

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

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


查看完整回答
反对 回复 2022-06-17
  • 2 回答
  • 0 关注
  • 126 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信