I recently ran into a problem that stopped me from having 100% test coverage on a file.
This is the piece of code, the overall reasoning for it can be found on the microtime manual page:
In case you did not spot it, the else path is never accessed if your system has a "microtime" function available. Additionally the change can be non-trivial because time() returns something like 1012314124 and microtime() returns "0.80057400 1257872321" or "1257872326.3036".
My first idea was something like this in the test case:
Then the idea was to use variable functions, but in the end I think it's not worth to change the source code to something less intelligable only to achieve 100% test coverage for a trivial case.
Of course you could always invoke a CLI php with a special php.ini if you have bigger chunks of code to be tested depending on the availability of certain functions.
Another idea could be to create a wrapper for microtime that you can mock and in your mock object always return the output of time() instead of microtime(), this would probably be the best tradeoff between readability and testability.
Any ideas?
This is the piece of code, the overall reasoning for it can be found on the microtime manual page:
This function is only available on operating systems that support the gettimeofday() system call.
In case you did not spot it, the else path is never accessed if your system has a "microtime" function available. Additionally the change can be non-trivial because time() returns something like 1012314124 and microtime() returns "0.80057400 1257872321" or "1257872326.3036".
My first idea was something like this in the test case:
Then the idea was to use variable functions, but in the end I think it's not worth to change the source code to something less intelligable only to achieve 100% test coverage for a trivial case.
Of course you could always invoke a CLI php with a special php.ini if you have bigger chunks of code to be tested depending on the availability of certain functions.
Another idea could be to create a wrapper for microtime that you can mock and in your mock object always return the output of time() instead of microtime(), this would probably be the best tradeoff between readability and testability.
Any ideas?
Posted by fa
in PHP
| Comments (11)
| Trackbacks (0)
Defined tags for this entry: code coverage, php
Related entries by tags:
PHP Unconference Hamburg 2009 - Nachlese
URL Shorteners
Blog-Software
Google App Engine
The XPath of Glory
PHP Unconference Hamburg 2009 - Nachlese
URL Shorteners
Blog-Software
Google App Engine
The XPath of Glory
Trackbacks
Trackback specific URI for this entry
No Trackbacks
Comments
Display comments as
(Linear | Threaded)
Having a code coverage of 100% does NOT mean that you wrote good tests, or test everything that you have to test.
IMHO you should simply ignore this.
But even if I would do some date calculations, there could be some error with parsing time() instead of microtime() - it's not about when to test, it's about how to test a problem like this.
Lets say you got a class Timer, with the methods startTimer(), startTimerTime(), startTimerMicrotime().
Within startTimer(), you check whether you got the microtime function or not, and then call startTimerTime or startTimerMicrotime.
In your UnitTests, you can test both: the time() and the microtime() method.
Note that at some point you will need to check if microtime() exists and provide the appropriate implementation - just don't do it in your business logic; do it in your bootstrap.
Code coverage has found a point in your code that is unreachable which means you need to refactor because your design is flawed; this is a good thing; this is why you do code coverage.
It is not unreachable per se. In this case it's platform-specific code. If I had tested on windows it would have been the other way round.
FYI, I'm using this line as a part of of a small profiler, which already is an addon to the actual application, I'd hardly call it business logic ;)
Apart from that I do agree, just that I surely won't start with interfaces here, I'd rather kick out microtime at all and just use time. The stuff profiled is probably running >1min anyway, so seconds is enough.
It's still just an example.
As you can see the piece of code remains a single statement, thus the coverage will be 100% as desired.
Use PHPT with an xUnit helper like much of PEAR2's code does, and you can simply do two tests, one with the --INI-- block, and one without:
--TEST--
test the thing with no microtime()
--INI--
disable_functions=microtime
--FILE--
===DONE===
--CLEAN--
--EXPECT--
===DONE===
Then again I did not double-check if there is some possibility to include a different php.ini or hack around it.
Thanks for the pointer.
I'd just remove the time() fallback. microtime() is being used in so many applications including SugarCRM and Magento that I seriously doubt that you'll run into trouble.
Thanks for the hint.
Layout by Ricky Wilson | Serendipity Template by Carl Galloway | Login
About
Life's a bitch, life's a whore. Nothing less, nothing more.
Read More
Der Autor...
... studiert Informatik. Und zwar an der LMU München. Das mittlerweile schon eine ganze Weile. Nebenher arbeitet er als PHP-Entwickler und Admin. Seit geraumer Zeit sogar regelmäßig und in Farbe
Quicksearch
last.fm
Song: Weather Experience (Top Buzz remix)
Artist: The Prodigy
14. June 2009, 19:23
Song: Charly (Trip Into Drum and Bass version)
Artist: The Prodigy
14. June 2009, 19:17
Song: Wind It Up (Rewound)
Artist: The Prodigy
14. June 2009, 19:11
9. February 2010, 12:36


