3

I have a function similar to this:

public function getSomeInfo($id){
    $date_start=new DateTime();
    $day_of_week=$date_start->format("N");
    $date_start=$date_start->sub(new DateInterval("P".$day_of_week."D"));
    $date_end=new $date_start;
    $date_end=$date_end->add(new DateInterval("P5D"));
    $date_start=$date_start->format("Y-m-d");
    $date_end=$date_end->format("Y-m-d");
    $sql="SELECT * FROM `table`  
            WHERE `table`.`id`=$id
            AND `session`.`date`>'$date_start'
            AND `session`.`date`<='$date_end'";
    $this->db->query($sql);
}

It returns a dataset for this current week, basically selects records from a table with a date between last Monday and This Sunday.

I want to be able to unit test this but I don't know how to do this when it is initiating a DateTime constructor. which will be for the current week but actually for testing purposes I only want one week of data in the testing dataset so really I want the test DateTime to be the same date every time.

Basically how can I set DateTime("now") to the same mock date everytime. I am using PHP, Codeigniter and PHPUnit/CIUnit (Implied in tags).

2 Answers 2

6

You could instead pass in the $date_start variable to the function, and when you call it in your test it would be the same every time ie

function testMymethod(){
   $date_start = new DateTime('2011-01-01');
   $class->getSomeInfo($id, $date_start);
   //assertions
}

And your method signiture would change to:

    class myclass {
      public function getSomeInfo($id, $date_start = new DateTime()){...}
    }
Sign up to request clarification or add additional context in comments.

2 Comments

Ah thanks, An example is worth a thousand words! An also this gives me the advantage of being able to use the same function for other weeks as well :)
I know it's a PHP limitation, but we're writing less explicit code just because PHP unit doesn't allows to mock global classes. A system like jest.mock on JS would be a way better solution, to be able to change the behavior of some modules for the tests without impacting the code readability.
6

There are (at least) 2 ways for this:

  1. Delegate the action of getting the current time into another class. Have a TimeProvider or similar class passed to the method, as an external dependency, or by using a ServiceContainer or whatever way you like, and in the test use a mock or even a TimeProvider subclass that behaves the way you want.

  2. Get the current time using a protected method and mock it (by creating a partial mock) of the subject under test.

I usually prefer the first way.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.