myol myol - 1 month ago 7
PHP Question

Mocking a wrapper time function

I have a created a minor wrapper function for the php

time()
method in my class

class MyClass
{
public function myFuncion($unixTimeStamp)
{
$pending = $this->isPending($unixTimeStamp)

// data manipulation

return $result
}

protected function isPending($unixTimeStamp)
{
if ($unixTimeStamp > $this->currentTime()) {
return true;
}

return false;
}

public function currentTime()
{
return time();
}
}


I want to test the public function
myFunction()
in this class but I am at a bit of a loss how I can mock the currentTime method without mocking the SUT itself (MyClass)

What is the correct way of doing this? I felt creating a time class with a single method (getCurrentTime) and injecting it into
MyClass
while correct, was excessive as I only check the time in one place in my code.

Is this the best method regardless?

EDIT: I am considering making a
time
trait as it looks like PhpUnit can mock this. Still unsure if this is overkill for use in a single method..

What other options do I have?

Answer

You can create a Partial mock object of your tested class in order to modify the behaviour only of the selected method (the currentTime method). For this purpose you can use the setMethods of the Mock Builder API:

setMethods(array $methods) can be called on the Mock Builder object to specify the methods that are to be replaced with a configurable test double. The behavior of the other methods is not changed. If you call setMethods(NULL), then no methods will be replaced.

So try this code (suppose the myFunction return the result of the isPending method):

class MyClassTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @test
     */
    public function itShouldReturnTrueIfPendingState()
    {
        $currentTime = (new \DateTime('now -1 year'))->getTimestamp();

        /** @var MyClass|\PHPUnit_Framework_MockObject_MockObject $myClass */
        $myClass = $this->getMockBuilder(MyClass::class)
            ->disableOriginalConstructor()
            ->setMethods(['currentTime'])
            ->getMock();

        $myClass
            ->method('currentTime')
            ->willReturn($currentTime);

        $this->assertTrue($myClass->myFunction(time()));
    }

    /**
     * @test
     */
    public function itShouldReturnFalseIfNotState()
    {
        $currentTime = (new \DateTime('now +1 year'))->getTimestamp();


        /** @var MyClass|\PHPUnit_Framework_MockObject_MockObject $myClass */
        $myClass = $this->getMockBuilder(MyClass::class)
            ->disableOriginalConstructor()
            ->setMethods(['currentTime'])
            ->getMock();

        $myClass
            ->method('currentTime')
            ->willReturn($currentTime);

        $this->assertFalse($myClass->myFunction(time()));
    }
Comments