Can I “Mock” time in PHPUnit?

后端 未结 11 460
梦谈多话
梦谈多话 2020-11-29 01:53

... not knowing if \'mock\' is the right word.

Anyway, I have an inherited code-base that I\'m trying to write some tests for that are time-based. Trying not to be <

相关标签:
11条回答
  • 2020-11-29 02:19

    For those of you working with symfony (>= 2.8): Symfony's PHPUnit Bridge includes a ClockMock feature that overrides the built-in methods time, microtime, sleep and usleep.

    See: http://symfony.com/doc/2.8/components/phpunit_bridge.html#clock-mocking

    0 讨论(0)
  • 2020-11-29 02:23

    Simplest solution would be to override PHP time() function and replace it with your own version. However, you cannot replace built-in PHP functions easily (see here).

    Short of that, the only way is to abstract time() call to some class/function of your own that would return the time you need for testing.

    Alternatively, you could run the test system (operating system) in a virtual machine and change the time of the entire virtual computer.

    0 讨论(0)
  • 2020-11-29 02:24

    You can overide php's time() function using the runkit extension. Make sure you set runkit.internal_overide to On

    0 讨论(0)
  • 2020-11-29 02:26

    I had to simulate a particular request in future and past date in the app itself (not in Unit Tests). Hence all calls to \DateTime::now() should return the date that was previously set throughout the app.

    I decided to go with this library https://github.com/rezzza/TimeTraveler, since I can mock the dates without altering all the codes.

    \Rezzza\TimeTraveler::enable();
    \Rezzza\TimeTraveler::moveTo('2011-06-10 11:00:00');
    
    var_dump(new \DateTime());           // 2011-06-10 11:00:00
    var_dump(new \DateTime('+2 hours')); // 2011-06-10 13:00:00
    
    0 讨论(0)
  • 2020-11-29 02:29

    Here's an addition to fab's post. I did the namespace based override using an eval. This way, I can just run it for tests and not the rest of my code. I run a function similar to:

    function timeOverrides($namespaces = array()) {
      $returnTime = time();
      foreach ($namespaces as $namespace) {
        eval("namespace $namespace; function time() { return $returnTime; }");
      }
    }
    

    then pass in timeOverrides(array(...)) in the test setup so that my tests only have to keep track of what namespaces time() is called in.

    0 讨论(0)
提交回复
热议问题