php - unit testing and Static methods -
reading , picking on unit testing, trying make sense of the following post on explains hardships of static function calls.
i don't understand issue. have assumed static functions nice way of rounding utility functions in class. example, use static functions calls initialise, ie:
init::loadconfig('settings.php'); init::seterrorhandler(app_mode); init::loggingmode(app_mode); // start loading app related objects .. $app = new app();
// after reading post, aim instead ...
$init = new init(); $init->loadconfig('settings.php'); $init->loggingmode(app_mode); // etc ...
but, few dozen tests had written class same. changed nothing , still pass. doing wrong?
the author of post states following:
the basic issue static methods procedural code. have no idea how unit-test procedural code. unit-testing assumes can instantiate piece of application in isolation. during instantiation wire dependencies mocks/friendlies replace real dependencies. procedural programing there nothing “wire” since there no objects, code , data separate.
now, understand post static methods create dependencies, don't grasp intuitively why 1 cannot test return value of static method regular method?
i avoiding static methods, of liked having idea of when static methods useful, if @ all. seems post static methods evil global variables , should avoided as possible.
any additional information or links on subject appreciated.
static methods aren't harder test instance methods. trouble arises when method--static or otherwise--calls other static methods because cannot isolate method being tested. here typical example method can difficult test:
public function finduser($id) { assert::valididentifier($id); log::debug("looking user $id"); // writes file database::connect(); // needs user, password, database info , database return database::query(...); // needs user table data }
what might want test method?
- passing other positive integer throws
invalididentifierexception
. database::query()
receives correct identifier.- a matching user returned when found,
null
when not.
these requirements simple, must setup logging, connect database, load data, etc. database
class should solely responsible testing can connect , query. log
class should same logging. finduser()
should not have deal of this, must because depends on them.
if instead method above made calls instance methods on database
, log
instances, test pass in mock objects scripted return values specific test @ hand.
function testfinduserreturnsnullwhennotfound() { $log = $this->getmock('log'); // ignore logging calls $database = $this->getmock('database', array('connect', 'query'); $database->expects($this->once())->method('connect'); $database->expects($this->once())->method('query') ->with('<query string>', 5) ->will($this->returnvalue(null)); $dao = new userdao($log, $database); self::assertnull($dao->finduser(5)); }
the above test fail if finduser()
neglects call connect()
, passes wrong value $id
(5
above), or returns other null
. beauty no database involved, making test quick , robust, meaning won't fail reasons unrelated test network failure or bad sample data. allows focus on matters: functionality contained within finduser()
.
Comments
Post a Comment