Is it possible to make a PHP application think that the server datetime is offset by a large configurable amount (like 6 months ago, or 6 months from now)?
Background:
We have a web application that deals with sporting events and right now we would like to run it in our development environment in such a way that the web site thinks it is Fall 2009 instead of Summer 2010. That's because we have great data from last year's Fall season and this year's season has not yet started, so testing new features would be easier with scads of real data instead of making up new test data for 2010.
We don't want to actually change the server's date and time. The current best option seems to be to change all date() calls in the code to my_date() and then have my_date() add the offset to the actual system date.
It seemed like this feature would be useful in similar situations for others, so I was just curious if there's an easier way to do it globally through some configuration parameter without modifying code. I did RTM.
You could install Runkit on the Development server and redefine all required dateTime functions to return a modified value, e.g.
if(APP_ENV === 'testing') {
include 'datetime-monkeypatches.php';
}
where datetime-monkeypatches.php would contain your patches to the required functions. This way you wouldnt have to change your actual code. It's like using an adapter to the original functions and as long as you keep them in that separate file, it stays maintainable.
Another option would be to use http://antecedent.github.io/patchwork
Patchwork is a PHP library that makes it possible to redefine user-defined functions and methods at runtime, loosely replicating the functionality runkit_function_redefine in pure PHP 5.3 code, which, among other things, enables you to replace static and private methods with test doubles.
I've never tried it, but maybe libfaketime could help, here : it allows one to "fake" the time for a process.
For example, see this article : Changing what time a process thinks it is with libfaketime
But, as said in this ticket of PHPUnit's Trac, that's probably something that should be done using your own equivalent of dates functions...
Which means, like you guessed, that the best solution, if you can afford it, would indeed be to use your own my_date() function everywhere.
You could use a custom DateTime class:
class My_DateTime extends DateTime
{
public static $timeModifier = NULL;
public function __construct($now = 'now', DateTimeZone $timezone = NULL)
{
parent::__construct($now);
if($timezone !== NULL) {
$this->setTimezone($timezone);
}
if(self::$timeModifier !== NULL) {
$this->modify(self::$timeModifier);
}
}
}
In your bootstrap simply set the $timeModifier like this:
if(APP_ENV === 'testing') {
My_DateTime::$timeModifier = '-6 months';
}
And then you can use it like this from anywhere:
$now = new My_DateTime();
echo $now->format('Y-m-d H:i:s'); // 2010-01-17 16:41:49
Related
You may wonder why I would want to do this. I'm trying to debug PHP performance on an embedded system. Don't have access to any kind of tools on the device.
I was thinking if I could just do a simple microseconds calculation on every call, it would work.
Is there a way to do it? Essentially wrap all of my functions (not built in php).
This wouldn't be for production of course.
You can use declare(ticks=1000); to run an callback, like:
// you can use this:
declare(ticks=1);
// A function called on each tick event
function tick_handler()
{
debug_backtrace();//get function name
microtime();//get time
}
http://www.php.net/declare
you only have to get the right number e.g. 1000 for your tests cycles
UberCart for Drupal has some difficulties with currencies. However, by overriding "uc_currency_format", you can at least do some background calculation to give you a good estimate of the converted value. However, as it's part of UberCart Core, you can't edit the file, So you risk losing your code after every update. Also, this function does not have a hook!
That means the only that I can think of dealing with this, is having a module that overrides the function. So my question is...
Is there a way to override an existing PHP function? For example, I have:
function uc_currency_format($value, $sign = TRUE, $thou = TRUE, $dec = NULL)
{
// dont do this
}
But when this gets called, I want it to instead execute this
function uc_currency_format_rewrite($value, $sign = TRUE, $thou = TRUE, $dec = NULL)
{
// do this
}
Is that possible?
It seems to be one of those very rare times you need to hack the core code.
When it comes to this, I try to limit the impact at minimum like this:
Rename original function. In your case, you would go with something like 'uc_currency_format_ORIGINAL'
In your custom module, rename your 'uc_currency_format_rewrite' into 'uc_currency_format'
This way, you will have your own code running.
At next update, you will see in your testing environment (always better to test, before applying updates to production sites) a duplicate function name fatal error. If your hook has not been implemented yet, you will rename the original fuction, again.
This method is not defined in the best practice, of course. Use it at your own risk.
No it is not possible to override a function in PHP. Drupal 7 does not use Zend (rename_function(), override_function()) or OOP in modules. So you could only ask the maintainer for a new hook.
Maybe you could write a patch, which provides this hook and ask the maintainer for implementing it.
Firstly, I will say that I come from the Java world (this is important, really).
I have been coding PHP for a while, one of the problems that I have encountered is that due to the lack of compilation, sometimes errors that could be easily detected at compilation time (for example, wrong number of parameters for a given function), can silently pass.
That could be easily detected as code coverage increases by adding unit tests. The question is, does it make sense for example to tests constructors in order to check that the passed parameters are correct? I do not mean only the number of parameters, but also the content of such parameters (for example, if a parameter is null, certain objects should launch an exception in order to avoid creating a "dirty" object).
Question is, am I too contaminated by years of Java code? Because after all, increasing the code coverage to "discover" missued functions feels like a (really) primitive way of compiling.
Also, I would like to note that I already use a development environment (PHPStorm), we are also using tools like PHPCodeSniffer.
Any ideas/suggestions?
This is a good question that can be answered on a number of levels:
Language characteristics
Test coverage
CASE tools
1. Language characteristics
As you have pointed out the characteristics of the PHP language differ markedly from the more strongly-typed languages such as Java. This raises a serious issue where programmers coming from the more strongly-typed languages such as Java and C# may not be aware of the implications of PHP's behaviour (such as those you have described). This introduces the possibility of mistakes on the part of the programmer (for example, a programmer who may have been less careful using Java because they know the compiler will catch incorrect parameters may not apply the appropriate care when developing in PHP).
Consequently, better programmer education/supervision is needed to address this issue (such as in-house company coding standards, pair programming, code review). It also (as you have pointed out) raises the question of whether test coverage should be increased to check for such mistakes as would have been caught by a compiler.
2. Test Coverage
The argument for test coverage is very project-specific. In the real world, the level of test coverage is primarily dictated by the error tolerance of the customer (which is dictated by the consequences of an error occuring in your system). If you are developing software that is to run on a real-time control system, then obviously you will test more. In your question you identify PHP as the language of choice; this could apply equally to the ever-increasing number of web-enabled frontends for critical systems infrastructure. On the other side of the coin, if you are developing a simple website for a model railroad club and are just developing a newsletter app then your customer may not care about the possibility of a bug in the constructor.
3. CASE Tools
Ultimately it would be desirable for a CASE tool to be available which can detect these errors, such as missing parameters. If there are no suitable tools out there, why not create one of your own. The creation of a CASE tool is not out of reach of most programmers, particularly if you can hook into an open-source parsing engine for your language. If you are open-source inclined this may be a good project to kick start, or perhaps your company could market such a solution.
Conclusion
In your case whether or not to test the constructors basically comes down to the question: what will the consequences of a failure in my system be? If it makes financial sense to expend extra resources on testing your constructors in order to avoid such failures, then you should do so. Otherwise it may be possible to get by with lesser testing such as pair programming or code reviews.
Do you want the constructor to throw an exception if invalid parameters set? Do you want it to behave that same way tomorrow and next week and next year? Then you write a test to verify that it does.
Tests verify that your code behaves as you want it to. Failing on invalid parameters is code behavior just as much as calculating sales tax or displaying a user's profile page.
We test constructors, as well as the order of the parameters, the defaults when not provided, and then some actual settings. For instance:
class UTIL_CATEGORY_SCOPE extends UTIL_DEPARTMENT_SCOPE
{
function __construct($CategoryNo = NULL, $CategoryName = NULL)
{
parent::__construct(); // Do Not Pass fields to ensure that the array is checked when all fields are defined.
$this->DeclareClassFields_();
$this->CategoryName = $CategoryName;
$this->CategoryNo = $CategoryNo;
}
private function DeclareClassFields_()
{
$this->Fields['CategoryNo'] = new UTIL_ICAP_FIELD_PAIR_FIRST('CCL', 6, ML('Category'), 8);
$this->Fields['CategoryName'] = new UTIL_ICAP_FIELD_PAIR_SECOND('CCL', 32, ML('Name'), 15, array(), array(), NULL, UTIL_ICAP_FIELD::EDIT_DENY, UTIL_ICAP_FIELD::UPDATE_DENY, 'DES');
}
}
We then create our tests to not only check the constructor and its order, but that class and inheritance has not changed.
public function testObjectCreation()
{
$CategoryInfo = new UTIL_CATEGORY_SCOPE();
$this->assertInstanceOf('UTIL_CATEGORY_SCOPE', $CategoryInfo);
$this->assertInstanceOf('UTIL_DEPARTMENT_SCOPE', $CategoryInfo);
$this->assertInstanceOf('UTIL_DATA_STRUCTURE', $CategoryInfo); // Inherited from UTIL_DEPARTMENT_SCOPE
}
public function testConstructFieldOrder()
{
$CategoryInfo = new UTIL_CATEGORY_SCOPE(1500, 'Category Name');
$this->assertEquals(1500, $CategoryInfo->CategoryNo);
$this->assertEquals('Category Name', $CategoryInfo->CategoryName);
}
public function testConstructDefaults()
{
$CategoryInfo = new UTIL_CATEGORY_SCOPE();
$this->assertNull($CategoryInfo->CategoryNo);
$this->assertNull($CategoryInfo->CategoryName);
}
public function testFieldsCreated()
{
$CategoryInfo = new UTIL_CATEGORY_SCOPE();
$this->assertArrayHasKey('CategoryNo', $CategoryInfo->Fields);
$this->assertArrayHasKey('CategoryName', $CategoryInfo->Fields);
$this->assertArrayHasKey('DeptNo', $CategoryInfo->Fields); // Inherited from Parent
$this->assertArrayHasKey('DeptName', $CategoryInfo->Fields); // Inherited from Parent
}
I'm working on a class-based php web app. I have some places where objects are interacting, and I have certain situations where I'm using error codes to communicate to the end user -- typically when form values are missing or invalid. These are situations where exceptions are unwarranted ( and I'm not sure I could avoid the situations with exceptions anyways).
In one object, I have some 20 code numbers, each of which correspond to a user-facing message, and a admin/developer-facing message, so both parties know what's going on. Now that I've worked over the code several times, I find that it's difficult to quickly figure out what code numbers in the series I've already used, so I accidentally create conflicting code numbers. For instance, I just did that today with 12, 13, 14 and 15.
How can I better organize this so I don't create conflicting error codes? Should I create one singleton class, errorCodes, that has a master list of all error codes for all classes, systematizing them across the whole web app? Or should each object have its own set of error codes, when appropriate, and I just keep a list in the commentary of the object, to use and update that as I go along?
Edit: So I'm liking the suggestions to use constants or named constants within the class. That gives me a single place where I programatically define and keep track of error codes and their messages.
The next question: what kind of interface do I provide to the outside world for this class' error codes and messages? Do I do something like triggerError(20) in the class, and then provide a public method to return the error code, the string constant, and the user- and admin-facing message?
You could create a couple of defines to create named constants for all your error codes :
define('ERROR_CODE_SQL_QUERY', 1);
define('ERROR_CODE_PAGE_NOT_FOUND', 2);
define('ERROR_CODE_NOT_ALLOWED', 3);
// and so on
And, then, use the constants in your code :
if ($errorCode == ERROR_CODE_SQL_QUERY) {
// deal with SQL errors
}
With that, nowhere in your code you'll use the numerical value : everywhere (except in the on and only file where you put the defines), you'll use the codes.
It means :
Less risk of errors, as all numerical values are set in only one file
Less risk of errors, as you'll use the constants, that have a name which indicates what it means
And code that's easier to read.
Another idea could be to create a class to deal with errors :
class Error {
const CODE_SQL_QUERY = 1;
const CODE_PAGE_NOT_FOUND = 2;
const CODE_NOT_ALLOWED = 3;
// Add some methods here, if needed
}
And, then, use something like this :
if ($errorCode == Error::CODE_SQL_QUERY) {
// deal with SQL errors
}
Which one is the best ?
It's probably a matter of personnal preferences... If you need to add some methods to deal with the errors, using a class might be useful. Else, defines are a great solution too.
At the very least, can you bump the code numbers up to be class constants or members?
class MyErrorProneClass {
const TURNED_INTO_A_NEWT = 12;
...
public function dontBurnMe() {
// echo your error here using self::TURNED_INTO_A_NEWT
}
This way you can manage the errors in the same place where you use them, rather than having to maintenance a large central file. I tried something to that effect in the past and it becomes difficult to keep up.
Generating error numbers programmatically may be a better long-term solution. If you could use information about the file or line number (__FILE__ and __LINE__ respectively), that would help.
Hope that moves in the right direction at least.
Thanks, Joe
Edit:
A class member would follow this syntax instead:
class MyErrorProneClass {
protected static $turnedIntoANewt = 12;
...
public function dontBurnMe() {
// echo your error here using self::$turnedIntoANewt
}
Since constants are public by default, you can access them from other classes directly if you want. So, from the outside, the error would be referenced as:
MyErrorProneClass::TURNED_INTO_A_NEWT
For associating to messages, you would use a mapping (either in a database, or in some localization file) from error ID (and frontend/backend) to displayed string. This use of keys for messages isn't optimal, but it would allow you to change error messages without changing code as well.
If you don't know already it might be an idea to use trigger_error (), plus an error handler if you want to present the user with a better error message.
Have you thought about using exceptions? They may be a good choice for your problem here although adding them to your project now would probably require some restructuring.
You can extend the basic exception class so it fits your problem in terms the of user / developer error message separation.
... 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 too vague, the code is related to looking at the history of an item and determining if that item has now based a time threshold.
At some point I also need to test adding something to that history and checking that the threshold is now changed (and, obviously, correct).
The problem that I'm hitting is that part of the code I'm testing is using calls to time() and so I'm finding it really hard to know exactly what the threshold time should be, based on the fact that I'm not quite sure exactly when that time() function is going to be called.
So my question is basically this: is there some way for me to 'override' the time() call, or somehow 'mock out' the time, such that my tests are working in a 'known time'?
Or do I just have to accept the fact that I'm going to have to do something in the code that I'm testing, to somehow allow me to force it to use a particular time if need be?
Either way, are there any 'common practices' for developing time-sensitive functionality that is test friendly?
Edit:
Part of my problem, too, is the fact that the time that things occurred in history affect the threshold. Here's an example of part of my problem...
Imagine you have a banana and you're trying to work out when it needs to be eaten by. Let's say that it will expire within 3 days, unless it was sprayed with some chemical, in which case we add 4 days to the expiry, from the time the spray was applied. Then, we can add another 3 months to it by freezing it, but if it's been frozen then we only have 1 day to use it after it thaws.
All of these rules are dictated by historical timings. I agree that I could use the Dominik's suggestion of testing within a few seconds, but what of my historical data? Should I just 'create' that on the fly?
As you may or may not be able to tell, I'm still trying to get a hang of all of this 'testing' concept ;)
I recently came up with another 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
Carbon::setTestNow(Carbon $time = null) makes any call to Carbon::now() or new Carbon('now') return the same time.
https://medium.com/#stefanledin/mock-date-and-time-with-carbon-8a9f72cb843d
Example:
public function testSomething()
{
$now = Carbon::now();
// Mock Carbon::now() / new Carbon('now') to always return the same time
Carbon::setTestNow($now);
// Do the time sensitive test:
$this->retroEncabulator('prefabulate')
->assertJsonFragment(['whenDidThisHappen' => $now->timestamp])
// Release the Carbon::now() mock
Carbon::setTestNow();
}
The $this->retroEncabulator() function needs to use Carbon::now() or new Carbon('now') internally of course.
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
You can mock time for test using Clock from ouzo-goodies. (Disclaimer: I wrote this library.)
In code use simply:
$time = Clock::now();
Then in tests:
Clock::freeze('2014-01-07 12:34');
$result = Class::getCurrDate();
$this->assertEquals('2014-01-07', $result);
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
Personally, I keep using time() in the tested functions/methods. In your test code, just make sure to not test for equality with time(), but simply for a time difference of less than 1 or 2 (depending on how much time the function takes to execute)
You can overide php's time() function using the runkit extension. Make sure you set runkit.internal_overide to On
Using [runkit][1] extension:
define('MOCK_DATE', '2014-01-08');
define('MOCK_TIME', '17:30:00');
define('MOCK_DATETIME', MOCK_DATE.' '.MOCK_TIME);
private function mockDate()
{
runkit_function_rename('date', 'date_real');
runkit_function_add('date','$format="Y-m-d H:i:s", $timestamp=NULL', '$ts = $timestamp ? $timestamp : strtotime(MOCK_DATETIME); return date_real($format, $ts);');
}
private function unmockDate()
{
runkit_function_remove('date');
runkit_function_rename('date_real', 'date');
}
You can even test the mock like this:
public function testMockDate()
{
$this->mockDate();
$this->assertEquals(MOCK_DATE, date('Y-m-d'));
$this->assertEquals(MOCK_TIME, date('H:i:s'));
$this->assertEquals(MOCK_DATETIME, date());
$this->unmockDate();
}
In most cases this will do. It has some advantages:
you don't have to mock anything
you don't need external plugins
you can use any time function, not only time() but DateTime objects as well
you don't need to use namespaces.
It's using phpunit, but you can addapt it to any other testing framework, you just need function that works like assertContains() from phpunit.
1) Add below function to your test class or bootstrap. Default tolerance for time is 2 secs. You can change it by passing 3rd argument to assertTimeEquals or modify function args.
private function assertTimeEquals($testedTime, $shouldBeTime, $timeTolerance = 2)
{
$toleranceRange = range($shouldBeTime, $shouldBeTime+$timeTolerance);
return $this->assertContains($testedTime, $toleranceRange);
}
2) Testing example:
public function testGetLastLogDateInSecondsAgo()
{
// given
$date = new DateTime();
$date->modify('-189 seconds');
// when
$this->setLastLogDate($date);
// then
$this->assertTimeEquals(189, $this->userData->getLastLogDateInSecondsAgo());
}
assertTimeEquals() will check if array of (189, 190, 191) contains 189.
This test should be passed for correct working function IF executing test function takes less then 2 seconds.
It's not perfect and super-accurate, but it's very simple and in many cases it's enough to test what you want to test.
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.
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.
Disclaimer: I wrote this library.
If you are free to install php extensions in your system, you could then use https://github.com/slope-it/clock-mock.
That library requires ext-uopz >= 6.1.1 and by using ClockMock::freeze and ClockMock::reset you can move the internal php clock to whatever date and time you like. The cool thing about it is that it requires zero modifications to your production code because it mocks transparently \DateTime and \DateTimeImmutable objects as well as some of the global functions (e.g. date(), time(), etc...).
You can use libfaketime
https://github.com/wolfcw/libfaketime
LD_PRELOAD=src/libfaketime.so.1 FAKETIME="#2020-01-01 11:12:13" phpunit
It will be as if you changed your system clock but only for that process, and it will work regardless of how low level your phpcode is
(Except if they use an external API call to get the time of course !)