Melle
Melle

Reputation: 8357

Compare Objects with DateTime properties in PHPUnit

Suppose I have two objects with the following structure:

class Item {
     public $id;
     public $date;
}

In a unit test, I'd like to test the equality of two items. E.g.:

class MyTests extends PHPUnit\Framework\TestCase
{
    public function testDummy() {
        $item1 = new Item();
        $item1->id = 1000;
        $item1->date = new DateTimeImmutable('now');

        $item2 = new Item();
        $item2->id = 1000;
        $item2->date = $item1->date->modify('+1 second');

        // For my use case, I'd consider these two items equal.
        $this::assertEquals($item1, $item2); // FAILURE :(
}

Is there a clean/simple way compare these objects and use a delta in case PHPUnit encounters a DateTime object?

I know I can use $this::assertEquals($item1->date, $item2->date, '', 10) but given my object I'd rather not write assertions for each property.

Thanks!

Upvotes: 2

Views: 4220

Answers (3)

gstoert
gstoert

Reputation: 138

I'd suggest to implement an equals method in your Item class and just test for its return value in your test like this:

class MyTests extends PHPUnit\Framework\TestCase
{
    public function testDummy() {
        $item1 = new Item();
        $item1->id = 1000;
        $item1->date = new DateTimeImmutable('now');

        $item2 = new Item();
        $item2->id = 1000;
        $item2->date = $item1->date->modify('+1 second');

        $this->asserTrue($item1->equals($item2));
        $this->asserTrue($item2->equals($item1));
    }
}

for an Item similar to this one:

class Item
{
    const OFFSET_TOLERANCE = 1;

    public $id;
    public $date;

    public function equals(self $item): bool
    {
        // in case the id is relevant as well
        if ($this->id !== $item->id) {
            return false;
        }

        // not sure how you prefer to handle the following 2 cases
        if (null === $item->date && null === $this->date) {
            return true;
        }

        if (!($this->date instanceof DateTimeInterface) ||
            !($item->date instanceof DateTimeInterface))
        {
            return false;
        }

        $interval = $this->date->diff($item->date);

        // note that you can also use $interval->f
        // to compare microseconds since PHP 7.1
        return $interval->s > self::OFFSET_TOLERANCE;
    }
}

Unfortunately there is no __equals method like in Java.

The only alternative solution I can think of is to implement a __toString method that returns a somehow representative value of your Item object, containing i.e. the timestamp without the last digit.

But in terms of readability and reliability and to ensure you are explicit about your implementation, I recommend to go for a solution similar to the example above.

Upvotes: 1

Marylyn Lajato
Marylyn Lajato

Reputation: 1171

Not sure what will be the basis on the type of [test result] you need to for this given test case. But if you want to test if both objects are equal:

  • Compare the two objects based on its [instance]
  • If there's a case that one property uses the [DateTime] object

Then I would propose the ff. assertions:

class MyTests extends PHPUnit\Framework\TestCase
{
    public function testDummy() {
        $item1 = new Item();
        $item1->id = 1000;
        $item1->date = new DateTimeImmutable('now');

        $item2 = new Item();
        $item2->id = 1000;
        $item2->date = $item1->date->modify('+1 second');

        // Option 1: Check if given object is an instance of [Item] class
        $this::assertEquals($item1 instanceof Item, $item2 instanceof Item);

        // Option 2: Check if given property for each assigned variables is an instance of [DateTimeImmutable] class
        $this::assertEquals($item1->date instanceof DateTimeImmutable, $item2->date instanceof DateTimeImmutable);
    }
}

Hope this will guide you well.

Upvotes: 0

Krunal Pandya
Krunal Pandya

Reputation: 234

$item1= date('D, d M Y');

$item2 = date('D, d M Y', strtotime("+1 day"));

try this

Upvotes: 0

Related Questions