How can I change the current time (i.e. the output of time()
) in PHP for unit-testing date-manipulation-class?
I recently came up with a solution that is great if you are using PHP 5.3 namespaces. You can implement a new time() function inside your current namespace and create a shared resource where you set the return value in your tests. Then any unqualified call to time() will use your new function.
For further reading I described it in detail in my blog
Sounds like you need to remove the dependency of time()
from your date manipulation class
My guess is you are struggling with your dependencies. It looks like you are using the time() function inside your class while with unit testing you want to make sure you control the output of the methods/classes that provide the time for you. I'd say create a Time class that provides you with the time and mock it into your unit tests.
You might consider an interface-based inheritance model:
interface iClock
{
public function getTime();
}
class SystemClock implements iClock
{
public function getTime()
{
return time();
}
}
class FakeClock implements iClock
{
private $time;
function __construct($time)
{
$this->time = $time;
}
public function getTime()
{
return $this->time;
}
// you could have more functions to advance the time, etc.
}
Your own classes that need to work with the current time would take a constructor parameter of the iClock
interface type.
class YourOwnClass
{
private $clock;
function __construct(iClock $clock)
{
$this->clock = $clock;
}
function someFunction()
{
$now = $this->clock->getTime();
// whatever
return $now;
}
}
Then you would simply inject the type of clock you wanted, depending on whether you were in a unit test or not:
$realWorldInstance = new YourOwnClass(new SystemClock());
echo $realWorldInstance->someFunction();
$unitTestInstance = new YourOwnClass(new FakeClock(1234));
echo $unitTestInstance->someFunction();
BTW - I use this pattern often in .NET as well. It's also built into the IClock
interface provided by Noda Time. I see no reason why this pattern wouldn't work in PHP. You might choose to return a DateTime
instead of just the integer timestamp, but the above is the minimal needed to use the pattern.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With